cloud-utils 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ v1.0. Initial release.
data/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ #
2
+ # Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13
+ # or implied. See the License for the specific language governing
14
+ # permissions and limitations under the License.
15
+ #
@@ -0,0 +1,14 @@
1
+ CHANGELOG
2
+ LICENSE
3
+ README.markdown
4
+ Rakefile
5
+ bin/deploy
6
+ bin/monitor
7
+ cloud-utils.tmproj
8
+ etc/deploy.yml
9
+ etc/monitor.yml
10
+ lib/cloud/deploy.rb
11
+ lib/cloud/deploy/artifact.rb
12
+ lib/cloud/deploy/monitor.rb
13
+ lib/cloud/logger.rb
14
+ Manifest
@@ -0,0 +1,53 @@
1
+ Ruby Cloud Artifact Deployer
2
+ =====
3
+
4
+ The purpose of this utility is to aid the developer in deploying artifacts into a hybrid cloud environment. If you have several instances of an application server running on different virtual machines, then you can use these utilities to facilitate that deployment. It respects ETags and won't download a resource it's already deployed before (unless you give it the "-f" options, which forces a deployment). It also respects MD5 sums and won't redeploy a resource it's downloaded if it has already deployed it before.
5
+
6
+ Config Files
7
+ -----
8
+
9
+ In order to be a little more secure, this system doesn't deploy arbitrary artifacts. You have to explicitly configure what you want downloaded and where you want it to go. There are two main configuration files: the "monitor.yml" file, which controls how the monitor watches for deployment notifications, and the "deploy.yml" file, which configures the deployer. They are both YAML files. An example config for the deployment monitor would be:
10
+
11
+ <pre><code>
12
+ default:
13
+ host: localhost
14
+ port: 5672
15
+ user: guest
16
+ password: guest
17
+ virtual_host: /
18
+ exchange: vcloud.deployment.events
19
+
20
+ myapp.war:
21
+ :deploy: deploy -e %s
22
+ </code></pre>
23
+
24
+ The "default" section handles the RabbitMQ connection info, as well as what exchange the artifacts will be publishing deployment notifications to (more on that when I get that part uploaded). Every other section is considered to be a deployment artifact. The name should correspond to the queue name being used to publish the notifications. In this example, your continuous integration server would publish a message with the MD5 hash of the file being deployed as the "correlation_id" and the artifact name (as configured in deploy.yml) as the body of the message. The "%s" in the deploy line is where the artifact name that comes from the AMQP message. That's optional. You could specify the artifact name (as configured in deploy.yml).
25
+
26
+ The deploy.yml file configures the deployer:
27
+
28
+ <pre><code>
29
+ myapp.war:
30
+ source: http://development/artifacts/myapp.war
31
+ destination:
32
+ - /opt/tcServer/tcServer-6.0/tc1/webapps
33
+ - /opt/tcServer/tcServer-6.0/tc2/webapps
34
+ - /opt/tcServer/tcServer-6.0/tc3/webapps
35
+
36
+ myapp.html:
37
+ unzip: true
38
+ source: http://development/artifacts/myapp-html.tar.gz
39
+ destination:
40
+ - /var/www/www.mycloud.mycompany.com/public
41
+ </code></pre>
42
+
43
+ Invoking the Deployment Mechanism
44
+ -----
45
+
46
+ To deploy a file (maybe, depending on MD5 sums and ETags), you first run the "monitor" script, which checks whether or not anything needs to be deployed. It will then execute whatever is defined in the YAML file's ":deploy" section. In this case, we're calling the other Ruby script in this package: "deploy", passing it the "-e" switch, which tells it to respect ETags and not download anything if there has been no change since the last deployment, and using the "%s" replacement character, where the artifact name will be passed when the message is processed.
47
+
48
+ When the deploy script is called by the monitor script, it downloads the artifact from the URL you configured in deploy.yml and either copies it directly to the list of destinations you give it, or unzips the file (if the artifact ends in ".tar.gz", it will be untarred, otherwise it will be unzipped) if you have configured "unzip: true".
49
+
50
+ License
51
+ -----
52
+
53
+ Apache 2.0 licensed. Just like the other cloud utilities.
@@ -0,0 +1,9 @@
1
+ require 'echoe'
2
+
3
+ Echoe.new('cloud-utils') do |pkg|
4
+ pkg.author = 'J. Brisbin'
5
+ pkg.email = 'jon@jbrisbin.com'
6
+ pkg.summary = 'Deploy artifacts in a cloud environment.'
7
+ pkg.url = 'http://github.com/jbrisbin/cloud-utils-deployer'
8
+ pkg.runtime_dependencies = ['amqp >=0.6.7']
9
+ end
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.expand_path("../../lib", __FILE__)
3
+ # puts "#{$:}"
4
+
5
+ require "optparse"
6
+ require "yaml"
7
+ require "cloud/logger"
8
+ require "cloud/deploy/artifact"
9
+
10
+ # Set command-line options
11
+ options = {}
12
+ optparse = OptionParser.new do |opts|
13
+ opts.banner = "Usage: deploy [options] artifact1 [artifact2] [...]"
14
+
15
+ options[:config] = '/etc/cloud/deploy.yml'
16
+ opts.on('-c', '--config CONFIG', 'Config file to read') do |config|
17
+ options[:config] = config
18
+ end
19
+
20
+ options[:etags] = false
21
+ opts.on('-e', '--etags', 'Respect ETag headers when downloading resources.') do
22
+ options[:etags] = true
23
+ end
24
+
25
+ options[:force] = false
26
+ opts.on('-f', '--force', 'Download and deploy this file irregardless of ETags and MD5 sums.') do
27
+ options[:force] = true
28
+ end
29
+
30
+ opts.on('-h', '--help', 'Display this help') do
31
+ puts opts
32
+ exit
33
+ end
34
+ end
35
+ optparse.parse!
36
+
37
+ config = YAML.load_file(options[:config])
38
+
39
+ ARGV.each do |arg|
40
+ artifact = Cloud::Deploy::Artifact.new
41
+ artifact.name = arg
42
+ artifact.uri = config[arg]['source']
43
+ artifact.local_paths = config[arg]['destination']
44
+ artifact.unzip = config[arg]['unzip']
45
+ artifact.force = options[:force]
46
+ artifact.use_etags = options[:etags]
47
+ if artifact.outdated?
48
+ artifact.deploy!
49
+ end
50
+ end
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.expand_path("../../lib", __FILE__)
3
+
4
+ require "optparse"
5
+ require "yaml"
6
+ require "cloud/logger"
7
+ require "cloud/deploy"
8
+ require "cloud/deploy/artifact"
9
+ require "cloud/deploy/monitor"
10
+ require "rubygems"
11
+ require "mq"
12
+
13
+ # Set command-line options
14
+ options = {}
15
+ optparse = OptionParser.new do |opts|
16
+ opts.banner = "Usage: monitor [options] [artifact1] [artifact...]"
17
+
18
+ options[:config] = '/etc/cloud/monitor.yml'
19
+ opts.on('-c', '--config CONFIG', 'Config file to read') do |config|
20
+ options[:config] = config
21
+ end
22
+
23
+ options[:force] = false
24
+ opts.on('-f', '--force', 'Disregard MD5 sums and force deployment') do
25
+ options[:force] = true
26
+ end
27
+
28
+ options[:timeout] = 5
29
+ opts.on('-t', '--timeout TIMEOUT', 'How many seconds to wait for subscriber threads to capture all messages') do |timeout|
30
+ options[:timeout] = timeout
31
+ end
32
+
33
+ opts.on('-h', '--help', 'Display this help') do
34
+ puts opts
35
+ exit
36
+ end
37
+ end
38
+ optparse.parse!
39
+
40
+ config = YAML.load_file(options[:config])
41
+ em_thread = Thread.new { EM.run }
42
+
43
+ # Use the name coming in on the command line or all of the configured names
44
+ names = Hash.new
45
+ if ARGV.size > 0
46
+ $log.info('deployer') { "Was passed artifacts to deploy, so using those: #{ARGV.join(', ')}" }
47
+ names.replace(ARGV)
48
+ else
49
+ $log.info('deployer') { "Deploying all configured artifacts" }
50
+ names.replace(config)
51
+ names.delete_if { |k, v| k == "default" }
52
+ end
53
+
54
+ monitors = []
55
+ names.each do |k, v|
56
+ mon = Cloud::Deploy::Monitor.new(config, k)
57
+ mon.deploy!
58
+ monitors << mon
59
+ end
60
+ em_thread.join(options[:timeout])
61
+
62
+ # Finish processing
63
+ Cloud::Deploy.load_md5sums do |md5s|
64
+ monitors.each do |mon|
65
+ if !mon.artifact.nil?
66
+ deploy_cmd = config[mon.name][:deploy] % mon.artifact
67
+ already_seen = md5s[mon.md5sum].nil?
68
+ if !options[:force] and already_seen
69
+ $log.info(mon.name) { "MD5 sums match, so not deploying again" }
70
+ else
71
+ $log.info(mon.name) { "Deploying: #{mon.artifact} with hash: #{mon.md5sum} using: #{deploy_cmd}" }
72
+ `#{deploy_cmd}`
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{cloud-utils}
5
+ s.version = "1.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["J. Brisbin"]
9
+ s.date = %q{2010-06-14}
10
+ s.description = %q{Deploy artifacts in a cloud environment.}
11
+ s.email = %q{jon@jbrisbin.com}
12
+ s.executables = ["deploy", "monitor"]
13
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.markdown", "bin/deploy", "bin/monitor", "lib/cloud/deploy.rb", "lib/cloud/deploy/artifact.rb", "lib/cloud/deploy/monitor.rb", "lib/cloud/logger.rb"]
14
+ s.files = ["CHANGELOG", "LICENSE", "README.markdown", "Rakefile", "bin/deploy", "bin/monitor", "cloud-utils.tmproj", "etc/deploy.yml", "etc/monitor.yml", "lib/cloud/deploy.rb", "lib/cloud/deploy/artifact.rb", "lib/cloud/deploy/monitor.rb", "lib/cloud/logger.rb", "Manifest", "cloud-utils.gemspec"]
15
+ s.homepage = %q{http://github.com/jbrisbin/cloud-utils-deployer}
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Cloud-utils", "--main", "README.markdown"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{cloud-utils}
19
+ s.rubygems_version = %q{1.3.7}
20
+ s.summary = %q{Deploy artifacts in a cloud environment.}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<amqp>, [">= 0.6.7"])
28
+ else
29
+ s.add_dependency(%q<amqp>, [">= 0.6.7"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<amqp>, [">= 0.6.7"])
33
+ end
34
+ end
@@ -0,0 +1,48 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>currentDocument</key>
6
+ <string>lib/cloud/deploy/artifact.rb</string>
7
+ <key>documents</key>
8
+ <array>
9
+ <dict>
10
+ <key>expanded</key>
11
+ <true/>
12
+ <key>name</key>
13
+ <string>cloud-utils</string>
14
+ <key>regexFolderFilter</key>
15
+ <string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
16
+ <key>sourceDirectory</key>
17
+ <string></string>
18
+ </dict>
19
+ </array>
20
+ <key>fileHierarchyDrawerWidth</key>
21
+ <integer>260</integer>
22
+ <key>metaData</key>
23
+ <dict>
24
+ <key>lib/cloud/deploy/artifact.rb</key>
25
+ <dict>
26
+ <key>caret</key>
27
+ <dict>
28
+ <key>column</key>
29
+ <integer>61</integer>
30
+ <key>line</key>
31
+ <integer>125</integer>
32
+ </dict>
33
+ <key>firstVisibleColumn</key>
34
+ <integer>0</integer>
35
+ <key>firstVisibleLine</key>
36
+ <integer>0</integer>
37
+ </dict>
38
+ </dict>
39
+ <key>openDocuments</key>
40
+ <array>
41
+ <string>lib/cloud/deploy/artifact.rb</string>
42
+ </array>
43
+ <key>showFileHierarchyDrawer</key>
44
+ <true/>
45
+ <key>windowFrame</key>
46
+ <string>{{270, 4}, {1410, 1024}}</string>
47
+ </dict>
48
+ </plist>
@@ -0,0 +1,12 @@
1
+ myapp.war:
2
+ source: http://development/artifacts/myapp.war
3
+ destination:
4
+ - /opt/tcServer/tcServer-6.0/tc1/webapps
5
+ - /opt/tcServer/tcServer-6.0/tc2/webapps
6
+ - /opt/tcServer/tcServer-6.0/tc3/webapps
7
+
8
+ myapp.html:
9
+ unzip: true
10
+ source: http://development/artifacts/myapp-html.tar.gz
11
+ destination:
12
+ - /var/www/www.mycloud.mycompany.com/public
@@ -0,0 +1,10 @@
1
+ default:
2
+ host: localhost
3
+ port: 5672
4
+ user: guest
5
+ password: guest
6
+ virtual_host: /
7
+ exchange: vcloud.deployment.events
8
+
9
+ myapp.war:
10
+ :deploy: deploy -e %s
@@ -0,0 +1,63 @@
1
+ #
2
+ # Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13
+ # or implied. See the License for the specific language governing
14
+ # permissions and limitations under the License.
15
+ #
16
+ require "cloud/logger"
17
+
18
+ module Cloud
19
+ module Deploy
20
+
21
+ ETAG_FILE = '/var/lib/cloud/deploy.etags'
22
+ MD5SUM_FILE = '/var/lib/cloud/deploy.md5sums'
23
+
24
+ def load_etags
25
+ etags = {}
26
+ if @use_etags
27
+ begin
28
+ File.open(ETAG_FILE, 'r') do |f|
29
+ etags = Marshal.load(f)
30
+ end
31
+ rescue => err
32
+ $log.fatal('etags') { err }
33
+ end
34
+ end
35
+ yield etags
36
+ end
37
+
38
+ def save_etags(etags)
39
+ File.open(ETAG_FILE, 'w') do |f|
40
+ f.write(Marshal.dump(etags))
41
+ end
42
+ end
43
+
44
+ def load_md5sums
45
+ md5sums = {}
46
+ begin
47
+ File.open(MD5SUM_FILE, 'r') do |f|
48
+ md5sums = Marshal.load(f)
49
+ end
50
+ rescue => err
51
+ $log.fatal('md5sums') { err }
52
+ end
53
+ yield md5sums
54
+ end
55
+
56
+ def save_md5sums(md5sums)
57
+ File.open(MD5SUM_FILE, 'w') do |f|
58
+ f.write(Marshal.dump(md5sums))
59
+ end
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,124 @@
1
+ #
2
+ # Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13
+ # or implied. See the License for the specific language governing
14
+ # permissions and limitations under the License.
15
+ #
16
+ require "cloud/logger"
17
+ require "cloud/deploy"
18
+ require "net/http"
19
+ require "uri"
20
+ require "fileutils"
21
+ include Cloud::Deploy
22
+
23
+ module Cloud
24
+ module Deploy
25
+
26
+ class Artifact
27
+
28
+ attr_reader :uri
29
+ attr_accessor :name, :local_paths, :unzip, :force, :use_etags
30
+
31
+ def initialize
32
+ @use_etags = true
33
+ end
34
+
35
+ def uri=(remote_uri)
36
+ @uri = URI.parse(remote_uri)
37
+ @http = Net::HTTP.new(@uri.host, @uri.port)
38
+ end
39
+
40
+ def outdated?
41
+ download
42
+ end
43
+
44
+ def deploy!
45
+ load_md5sums do |md5sums|
46
+ hash = md5sums[@name]
47
+ if !@force and !hash.nil? and hash == @hash
48
+ $log.info(@name) { "MD5 sums match. No need to deploy." }
49
+ else
50
+ @local_paths.each do |path|
51
+ FileUtils.mkdir_p(path)
52
+ if @unzip
53
+ $log.info(@name) { "Unzipping #{@name} to #{path}" }
54
+ if @uri.request_uri[-6..-1] == "tar.gz"
55
+ `tar -zxf #{@temp_file} -C #{path}`
56
+ else
57
+ `unzip -d #{path} #{@temp_file}`
58
+ end
59
+ else
60
+ $log.info(@name) { "Copying #{@name} to #{path}" }
61
+ FileUtils.cp(@temp_file, path)
62
+ end
63
+ end
64
+ md5sums[@name] = @hash
65
+ save_md5sums(md5sums)
66
+ end
67
+ # Clean up temp file
68
+ if !@temp_file.nil?
69
+ FileUtils.rm(@temp_file)
70
+ end
71
+ # We did a deployment
72
+ return true
73
+ end
74
+ # Default return
75
+ return false
76
+ end
77
+
78
+ private
79
+ def download
80
+ outdated = false
81
+
82
+ request = Net::HTTP::Get.new(@uri.request_uri)
83
+ load_etags do |etags|
84
+ etag = etags[@name]
85
+ if !@force and !etag.nil?
86
+ request.initialize_http_header({
87
+ 'If-None-Match' => etag
88
+ })
89
+ end
90
+
91
+ response = @http.request(request)
92
+ case response
93
+ when Net::HTTPSuccess
94
+ # Continue to download file...
95
+ $log.info(@name) { "Downloading: #{@uri.to_s}..." }
96
+ bytes = response.body
97
+ require "md5"
98
+ @hash = MD5.new.update(bytes).hexdigest
99
+ # Write to temp file, ready to deploy
100
+ @temp_file = "/tmp/#{@name}"
101
+ File.open(@temp_file, "w") { |f| f.write(bytes) }
102
+ # Update ETags
103
+ etags[@name] = response['etag']
104
+
105
+ outdated = true
106
+ when Net::HTTPNotModified
107
+ # No need to download it again
108
+ $log.info(@name) { "ETag matched, not downloading: #{@uri.to_s}" }
109
+ else
110
+ $log.fatal(@name) { "Error HTTP status code received: #{response['code']}" }
111
+ end
112
+
113
+ if @use_etags
114
+ save_etags(etags)
115
+ end
116
+ end
117
+
118
+ return outdated
119
+ end
120
+
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,57 @@
1
+ #
2
+ # Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13
+ # or implied. See the License for the specific language governing
14
+ # permissions and limitations under the License.
15
+ #
16
+ require "logger"
17
+ require "rubygems"
18
+ require "mq"
19
+ require "cloud/logger"
20
+ require "cloud/deploy"
21
+
22
+ module Cloud
23
+ module Deploy
24
+ class Monitor
25
+
26
+ attr_reader :md5sum, :artifact
27
+ attr_accessor :config, :name
28
+
29
+ def initialize(config, name)
30
+ @config = config
31
+ @name = name
32
+ @exchange = @config['default']['exchange']
33
+ end
34
+
35
+ def deploy!
36
+ defaults = @config['default']
37
+
38
+ # Connect to RabbitMQ...
39
+ host = defaults['host']
40
+ port = defaults['port']
41
+ user = defaults['user']
42
+ pass = defaults['password']
43
+ vhost = defaults['virtual_host']
44
+ exchange = defaults['exchange']
45
+ $log.info(@name) { "Connecting to MQ h: #{host}, p: #{port}, u: #{user}, pw: #{pass}, v: #{vhost}, x: #{exchange}" }
46
+
47
+ AMQP.start(:host => host, :port => port, :user => user, :pass => pass, :vhost => vhost) do
48
+ MQ.queue(@name).bind(@exchange).subscribe(:ack => true) do |headers, body|
49
+ @md5sum = headers.properties[:correlation_id]
50
+ @artifact = body
51
+ end
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,18 @@
1
+ #
2
+ # Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13
+ # or implied. See the License for the specific language governing
14
+ # permissions and limitations under the License.
15
+ #
16
+ require "logger"
17
+
18
+ $log = Logger.new('/var/log/cloud/deployer.log')
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloud-utils
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ version: "1.0"
10
+ platform: ruby
11
+ authors:
12
+ - J. Brisbin
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-14 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: amqp
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 9
29
+ segments:
30
+ - 0
31
+ - 6
32
+ - 7
33
+ version: 0.6.7
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description: Deploy artifacts in a cloud environment.
37
+ email: jon@jbrisbin.com
38
+ executables:
39
+ - deploy
40
+ - monitor
41
+ extensions: []
42
+
43
+ extra_rdoc_files:
44
+ - CHANGELOG
45
+ - LICENSE
46
+ - README.markdown
47
+ - bin/deploy
48
+ - bin/monitor
49
+ - lib/cloud/deploy.rb
50
+ - lib/cloud/deploy/artifact.rb
51
+ - lib/cloud/deploy/monitor.rb
52
+ - lib/cloud/logger.rb
53
+ files:
54
+ - CHANGELOG
55
+ - LICENSE
56
+ - README.markdown
57
+ - Rakefile
58
+ - bin/deploy
59
+ - bin/monitor
60
+ - cloud-utils.tmproj
61
+ - etc/deploy.yml
62
+ - etc/monitor.yml
63
+ - lib/cloud/deploy.rb
64
+ - lib/cloud/deploy/artifact.rb
65
+ - lib/cloud/deploy/monitor.rb
66
+ - lib/cloud/logger.rb
67
+ - Manifest
68
+ - cloud-utils.gemspec
69
+ has_rdoc: true
70
+ homepage: http://github.com/jbrisbin/cloud-utils-deployer
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options:
75
+ - --line-numbers
76
+ - --inline-source
77
+ - --title
78
+ - Cloud-utils
79
+ - --main
80
+ - README.markdown
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 11
98
+ segments:
99
+ - 1
100
+ - 2
101
+ version: "1.2"
102
+ requirements: []
103
+
104
+ rubyforge_project: cloud-utils
105
+ rubygems_version: 1.3.7
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: Deploy artifacts in a cloud environment.
109
+ test_files: []
110
+