vgh 0.0.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.
data/.gitignore ADDED
@@ -0,0 +1,28 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ html/
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+
20
+ # Mac Stuff
21
+ .DS_Store
22
+ .DS_Store?
23
+ ._*
24
+ .Spotlight-V100
25
+ .Trashes
26
+ Icon?
27
+ ehthumbs.db
28
+ Thumbs.db
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - 1.8.7
6
+ - ree
7
+ script: "rvmsudo bundle exec rake spec"
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --no-private --protected --readme=README.rdoc - LICENSE
2
+
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Vlad
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,121 @@
1
+ = VGH Scripts {<img src="https://secure.travis-ci.org/vladgh/vgh.png" alt="Build Status" />}[http://travis-ci.org/vladgh/vgh]
2
+
3
+ A collection of custom scripts used on VladGh.com
4
+
5
+
6
+ == Instalation
7
+
8
+ Some system wide dependencies should be installed first:
9
+
10
+ apt-get install libxslt-dev libxml2-dev
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'vgh'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install vgh
23
+
24
+
25
+ == Configuration
26
+
27
+ This gem looks for the following configuration files inside "+/etc/vgh+" or the
28
+ +--confdir+ specified in {VGH::CLI CLI Class}:
29
+
30
+ [+config.yml+]
31
+ The main configuration file for this gem.
32
+ <em>At this moment nothing needs to be configured here.</em>
33
+
34
+ [+aws.config.yml+]
35
+ The AWS specific configuration.
36
+ Available values:
37
+ - +:access_key_id+ - [String] Your AWS credentials
38
+ - +:secret_access_key+ - [String] Your AWS credentials
39
+ - +:region+ - optional [String] Your current instance's region.
40
+ Ex: +'us-west-1'+
41
+
42
+ [+#APP_NAME.config.yml+]
43
+ The application specific configuration (see below a list of available apps and
44
+ values).
45
+
46
+ This gem checks if the files exists and if they are in a correct YAML format.
47
+
48
+ All files should have the following format (where the keys are symbols):
49
+ # Comment
50
+ :key: 'value'
51
+ :string: 'string value'
52
+ :integer: 123
53
+ :boolean: true/false
54
+ :array:
55
+ - '1st'
56
+ - '2nd'
57
+ :hash:
58
+ -
59
+ :sub_key: 'sub value'
60
+
61
+
62
+ == Command line options
63
+
64
+ The following command line options are available:
65
+
66
+ [+ApplicationName+] Specify the application you want to run. For a
67
+ list of available apps see
68
+ {file:README.rdoc#Applications Applications} below.
69
+ [+-c+ <tt>--confdir '~/.vgh'</tt>] Specify the desired directory in which
70
+ the configuration files reside.
71
+ [+-v+ <tt>--[no-]verbose</tt>] Specify whether to display messages on the
72
+ screen or not.
73
+ [+-l+ <tt>--[no-]logging</tt>] Specify whether to log messages or not.
74
+ [+-h+ +--help+] Displays this list.
75
+ [+-V+ +--version+] Displays the version number.
76
+
77
+
78
+ == Applications
79
+
80
+ === EC2-Backup
81
+
82
+ [/bin/vgh ec2-backup]
83
+
84
+ ==== Description
85
+ This app creates a snapshot of the attached EBS volumes. It also deletes
86
+ snapshots older than the expiration period specified in the configuration
87
+ file. It is intended to be used as a cron job on an AWS instance running
88
+ Ubuntu.
89
+ If a MySQL server is running, and the script has access to the administrator
90
+ credentials, then it closes all open tables and locks all tables for all
91
+ databases with a global read lock. Everything is unlocked at the end of the
92
+ script even if errors occur during the snapshot process. <em>You need to
93
+ provide the necessary mysql credentials in the +ec2-backup.config.yml+ file.
94
+ </em>
95
+ If Logical Volumes are found on the system then they are suspended for the
96
+ duration on the snapshot process.
97
+ Suspending a volume becomes useful if you want for example a consistent
98
+ EC2 snapshot of it. Any I/O that has already been mapped by the device but
99
+ has not yet completed will be flushed. Any further I/O to that device will
100
+ be postponed for as long as the device is suspended.
101
+
102
+
103
+ ==== EC2-Backup Configuration
104
+ +ec2-backup.config.yml+
105
+ - +:expiration+ -- [Integer] Number of days to keep the snapshots.
106
+ # Ex:
107
+ :expiration: 7
108
+
109
+
110
+ ==== Intended usage
111
+ # Cron Job:
112
+ 0 */6 * * * vgh ec2-backup -l
113
+
114
+
115
+ == Contributing
116
+
117
+ 1. Fork it
118
+ 2. Create your feature branch (<tt>git checkout -b my-new-feature</tt>)
119
+ 3. Commit your changes (<tt>git commit -am 'Add some feature'</tt>)
120
+ 4. Push to the branch (<tt>git push origin my-new-feature</tt>)
121
+ 5. Create new Pull Request (http://help.github.com/articles/using-pull-requests)
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "yard"
4
+
5
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'tasks')
6
+ Dir['tasks/**/*.rake'].each { |task| load task }
7
+
8
+ RSpec::Core::RakeTask.new
9
+
10
+ task :default do
11
+ `rake -T`
12
+ end
13
+
14
+ task :test => :spec
15
+
16
+ desc 'Look for the @todo tag'
17
+ task :todo do |task|
18
+ Rake::Task['yard:doc_info'].execute
19
+ YARD::Registry.load!.all.each do |o|
20
+ todo = o.tag(:todo)
21
+ puts "#{todo.object} - #{todo.text}" if todo
22
+ end
23
+ end
24
+
25
+
data/bin/vgh ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'vgh'
4
+
5
+ include VGH
6
+ run
7
+
@@ -0,0 +1,63 @@
1
+ module VGH
2
+ module APPS
3
+
4
+ # == Description:
5
+ #
6
+ # See {file:README.rdoc#EC2-Backup EC2-Backup Section} in the README
7
+ # file.
8
+ #
9
+ # == Usage:
10
+ # backup = APPS::EC2_Backup.new
11
+ # backup.run
12
+ #
13
+ class EC2_Backup
14
+
15
+ # Loads the necessary classes
16
+ def initialize
17
+ $cfg = parse_config.app_config
18
+ @mysql = System::MySQL.new
19
+ @lv = System::LV.new
20
+ @volume = Extended_AWS::Extended_EC2::Volume.new
21
+ @snapshot = Extended_AWS::Extended_EC2::Snapshot.new
22
+ end
23
+
24
+ # Runs the ec2-backup app logic
25
+ def run
26
+ lock
27
+
28
+ begin
29
+ @volume.list.map {|id, info|
30
+ @snapshot.create(id, info[:tag])
31
+ }
32
+ rescue
33
+ message.fatal "Something went wrong in the snapshot creation process!"
34
+ end
35
+
36
+ unlock
37
+
38
+ @snapshot.purge
39
+ end
40
+
41
+ # Flushes MySQL tables and suspends Logical Volumes
42
+ def lock
43
+ @mysql.flush
44
+ @lv.suspend
45
+ end
46
+
47
+ # Resumes MySQL and Logical Volumes
48
+ def unlock
49
+ @mysql.unlock
50
+ @lv.resume
51
+ end
52
+
53
+ end # class EC2_Backup
54
+
55
+ end # module APPS
56
+ end # module VGH
57
+
58
+ require 'vgh/output'
59
+ require 'vgh/system/lvm'
60
+ require 'vgh/system/mysql'
61
+ require 'vgh/extended_aws/extended_ec2/volume'
62
+ require 'vgh/extended_aws/extended_ec2/snapshot'
63
+
data/lib/vgh/apps.rb ADDED
@@ -0,0 +1,22 @@
1
+ module VGH
2
+
3
+ # See {file:README.rdoc#Applications Applications Section} in the README
4
+ # file.
5
+ #
6
+ #
7
+ # == Usage:
8
+ # APPS.list
9
+ #
10
+ module APPS
11
+
12
+ # Lists the available applications
13
+ # @return [Array]
14
+ def self.list
15
+ @apps ||= [
16
+ 'ec2-backup'
17
+ ]
18
+ end
19
+
20
+ end # module APPS
21
+
22
+ end # module VGH
data/lib/vgh/cli.rb ADDED
@@ -0,0 +1,185 @@
1
+ require 'optparse'
2
+
3
+ module VGH
4
+
5
+ # Returns a global collection of options.
6
+ # @return [Hash]
7
+ def cli
8
+ $cli ||= CLI.new.options
9
+ end
10
+
11
+ # Returns the app name specified in the command line
12
+ # @return [String]
13
+ def app
14
+ $app ||= cli[:app]
15
+ end
16
+
17
+ # Returns the configuration specified in the command line
18
+ # @return [String]
19
+ def cli_confdir
20
+ $cli_confdir ||= cli[:confdir]
21
+ end
22
+
23
+ # Returns verbosity
24
+ # @return [Boolean]
25
+ def verbose?
26
+ $verbose = cli[:verbose]
27
+ end
28
+
29
+ # Returns logging
30
+ # @return [Boolean]
31
+ def logging?
32
+ $logging = cli[:logging]
33
+ end
34
+
35
+ # == Description:
36
+ #
37
+ # Returns a structure describing the command line options and arguments.
38
+ # See {file:README.rdoc#Command+line+options Command line options} in
39
+ # the README file.
40
+ #
41
+ #
42
+ # == Usage:
43
+ # cli = CLI.new.options
44
+ # puts cli[:app]
45
+ # puts cli[:verbose]
46
+ # puts cli[:logging]
47
+ # puts cli[:confdir]
48
+ #
49
+ class CLI
50
+
51
+ # Command line options
52
+ attr_reader :options
53
+
54
+ # We set default values here.
55
+ def defaults
56
+ @options[:app] = false
57
+ @options[:verbose] = false
58
+ @options[:logging] = false
59
+ end
60
+
61
+ # Collect options
62
+ # @param [Array] apps A list of available apps
63
+ # @param [String] app The name of the app
64
+ # @param [Array] args The command line arguments
65
+ def initialize(apps = APPS.list, app = ARGV[0], args = ARGV)
66
+ @options = {}
67
+ @optparse = OptionParser.new()
68
+ defaults
69
+ banner(apps)
70
+ confdir
71
+ verbose
72
+ logging
73
+ help
74
+ version
75
+ validate(args)
76
+ check_app(apps, app)
77
+ end
78
+
79
+ # Checks if the provided app is in the available list
80
+ def check_app(apps, app)
81
+ if apps.include? app
82
+ @options[:app] = app
83
+ else
84
+ puts "ERROR: You need to specify one of the following apps: \
85
+ #{apps.join(', ')}"
86
+ exit
87
+ end
88
+ end
89
+
90
+ # Returns the banner
91
+ def banner(apps)
92
+ header
93
+ available_apps(apps)
94
+ global_options
95
+ end
96
+
97
+ # Returns the header of the banner
98
+ def header
99
+ @optparse.banner = 'Usage: vgh app [options]'
100
+ @optparse.separator '========================'
101
+ end
102
+
103
+ # Returns a list of available apps
104
+ def available_apps(apps)
105
+ @optparse.separator ''
106
+ @optparse.separator "Available apps: #{apps.join(', ')}"
107
+ end
108
+
109
+ # Returns the header of the global options section
110
+ def global_options
111
+ @optparse.separator ''
112
+ @optparse.separator 'Options:'
113
+ end
114
+
115
+ # Loads the configuration directory
116
+ def confdir
117
+ @optparse.on('-c', '--confdir \'~/.vgh\'', 'Configuration directory') do |conf|
118
+ path = File.expand_path(conf)
119
+ @options[:confdir] = path if File.directory?(path)
120
+ end
121
+ end
122
+
123
+ # Loads the verbosity argument
124
+ def verbose
125
+ @optparse.on('-v', '--[no-]verbose', 'Run verbosely') do |verbose|
126
+ @options[:verbose] = verbose
127
+ end
128
+ end
129
+
130
+ # Loads the logging argument
131
+ def logging
132
+ @optparse.on('-l', '--[no-]logging', 'Enable logging') do |logging|
133
+ @options[:logging] = logging
134
+ end
135
+ end
136
+
137
+ # Loads the help argument
138
+ def help
139
+ @optparse.on_tail('-h', '--help', 'Show this message') do
140
+ show_help
141
+ end
142
+ end
143
+
144
+ # Loads the version argument
145
+ def version
146
+ @optparse.on_tail('-V', '--version', 'Show version') do
147
+ show_version
148
+ end
149
+ end
150
+
151
+ # Parses the arguments
152
+ def validate(args)
153
+ begin
154
+ @optparse.parse!(args)
155
+ rescue OptionParser::ParseError,
156
+ OptionParser::InvalidArgument,
157
+ OptionParser::InvalidOption,
158
+ OptionParser::MissingArgument
159
+ puts $!.to_s
160
+ show_help
161
+ exit
162
+ end
163
+ end
164
+
165
+ # Returns the help
166
+ def show_help
167
+ puts @optparse
168
+ puts ''
169
+ show_version
170
+ exit
171
+ end
172
+
173
+ # Returns a message with the script's version
174
+ def show_version
175
+ puts "VGH Scripts: v#{VGH::VERSION}"
176
+ exit
177
+ end
178
+
179
+ end # Class CLI
180
+
181
+ end # module VGH
182
+
183
+ require 'vgh/apps'
184
+ require 'vgh/version'
185
+
@@ -0,0 +1,176 @@
1
+ require 'aws-sdk'
2
+ require 'yaml'
3
+
4
+ require 'logger'
5
+
6
+ module VGH
7
+
8
+ # Initialize the configuration parser
9
+ def parse_config
10
+ $config ||= Configuration.new
11
+ end
12
+
13
+ # Returns a hash containing the main settings
14
+ def main_config
15
+ $main_config ||= parse_config.main_config
16
+ end
17
+
18
+ # Returns a hash containing the AWS settings
19
+ def aws_config
20
+ $aws_config ||= parse_config.aws_config
21
+ end
22
+
23
+ # Returns a hash containing the app settings
24
+ def app_config
25
+ $app_config ||= parse_config.app_config
26
+ end
27
+
28
+ # Returns a single merged hash with all configurations
29
+ def global_config
30
+ $global_config ||= [main_config, aws_config, app_config].inject(:merge)
31
+ end
32
+
33
+ # Creates a global ec2 method (passing the specified region).
34
+ # The default region is us-east-1, so we overwrite it here.
35
+ def ec2
36
+ region = aws_config[:region]
37
+ if region
38
+ $ec2 = AWS::EC2.new.regions[region]
39
+ else
40
+ $ec2 = AWS::EC2.new
41
+ end
42
+ end
43
+
44
+ # == Description:
45
+ #
46
+ # See {file:README.rdoc#Configuration Configuration Section} in the
47
+ # README file.
48
+ #
49
+ #
50
+ # == Usage:
51
+ #
52
+ # cfg = Configuration.new
53
+ # main_config = cfg.main_config
54
+ # aws_config = cfg.aws_config
55
+ # app_config = cfg.app_config
56
+ #
57
+ # pp main_config
58
+ # pp aws_config
59
+ # pp app_config
60
+ #
61
+ class Configuration
62
+
63
+ # Main configuration
64
+ attr_reader :main_config
65
+
66
+ # AWS configuration
67
+ attr_reader :aws_config
68
+
69
+ # App specific configuration
70
+ attr_reader :app_config
71
+
72
+ # Set defaults
73
+ def initialize
74
+ @confdir = validate_config_dir('/etc/vgh')
75
+ @main = "#{@confdir}/config.yml"
76
+ @aws = "#{@confdir}/aws.config.yml"
77
+ @app = "#{@confdir}/#{app}.config.yml"
78
+ end
79
+
80
+ # IF specified, use the confdir specified in the command line options
81
+ def validate_config_dir(default_confdir, cli = cli_confdir)
82
+ if cli.nil?
83
+ return default_confdir
84
+ else
85
+ return cli
86
+ end
87
+ end
88
+
89
+ # Returns error if the configuration is not right
90
+ def validate(cfg)
91
+ unless config_exists?(cfg) and config_correct?(cfg)
92
+ puts load_error(cfg)
93
+ exit 1
94
+ end
95
+ end
96
+
97
+ # Returns a parsed configuration
98
+ def parse(path)
99
+ @parse = YAML.load(File.read(path))
100
+ end
101
+
102
+ # Checks if the configuration file exists
103
+ def config_exists?(path)
104
+ File.exist?(path)
105
+ end
106
+
107
+ # Checks if the configuration is a valid YAML file
108
+ def config_correct?(path)
109
+ parse(path).kind_of?(Hash)
110
+ end
111
+
112
+ # Parse the main configuration
113
+ def main_config
114
+ message.info "Loading main configuration..."
115
+ validate(@main)
116
+ parse(@main)
117
+ end
118
+
119
+ # Parse the AWS configuration
120
+ def aws_config
121
+ message.info "Loading AWS configuration..."
122
+ validate(@aws)
123
+ @aws_config = parse(@aws)
124
+ load_aws
125
+ return @aws_config
126
+ end
127
+
128
+ # Overwrite the AWS Core configuration
129
+ def load_aws
130
+ AWS.config(@aws_config)
131
+ AWS.config({
132
+ :logger => log,
133
+ :log_formatter => AWS::Core::LogFormatter.colored,
134
+ :max_retries => 2
135
+ })
136
+ end
137
+
138
+ # Parse app specific configuration
139
+ def app_config
140
+ message.info "Loading #{app} configuration..."
141
+ validate(@app)
142
+ @app_config = parse(@app)
143
+ end
144
+
145
+ # Returns the error message in case the configuration os not right
146
+ def load_error(path)
147
+ log.fatal("#{path} is either missing or formatted incorrectly!")
148
+ load_error = <<END
149
+ #{path} is either missing or formatted incorrectly!
150
+
151
+ To run this script, you need to create a file named
152
+ #{path} with your configuration in the following format:
153
+
154
+ # Comment
155
+ :key: 'value'
156
+ :string: 'string value'
157
+ :integer: 123
158
+ :boolean: true/false
159
+ :array:
160
+ - '1st'
161
+ - '2nd'
162
+ :hash:
163
+ -
164
+ :sub_key: 'sub value'
165
+
166
+ END
167
+ end
168
+
169
+ end # class Configuration
170
+
171
+ end # module VGH
172
+
173
+ require 'vgh/cli'
174
+ require 'vgh/output'
175
+ require 'vgh/logging'
176
+