engineyard-visualvm 0.5.3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +5 -0
  2. data/ChangeLog +22 -0
  3. data/Gemfile +26 -0
  4. data/LICENSE.txt +23 -0
  5. data/README.md +104 -0
  6. data/Rakefile +124 -0
  7. data/Vagrantfile +94 -0
  8. data/bin/ey-visualvm +9 -0
  9. data/cookbooks/apt/README.md +122 -0
  10. data/cookbooks/apt/files/default/apt-cacher +9 -0
  11. data/cookbooks/apt/files/default/apt-cacher.conf +144 -0
  12. data/cookbooks/apt/files/default/apt-proxy-v2.conf +50 -0
  13. data/cookbooks/apt/metadata.json +34 -0
  14. data/cookbooks/apt/metadata.rb +13 -0
  15. data/cookbooks/apt/providers/repository.rb +73 -0
  16. data/cookbooks/apt/recipes/cacher-client.rb +44 -0
  17. data/cookbooks/apt/recipes/cacher.rb +45 -0
  18. data/cookbooks/apt/recipes/default.rb +50 -0
  19. data/cookbooks/apt/resources/repository.rb +30 -0
  20. data/cookbooks/gems/recipes/default.rb +16 -0
  21. data/cookbooks/java/README.md +102 -0
  22. data/cookbooks/java/attributes/default.rb +29 -0
  23. data/cookbooks/java/files/default/java.seed +11 -0
  24. data/cookbooks/java/metadata.json +50 -0
  25. data/cookbooks/java/metadata.rb +16 -0
  26. data/cookbooks/java/recipes/default.rb +21 -0
  27. data/cookbooks/java/recipes/openjdk.rb +39 -0
  28. data/cookbooks/java/recipes/sun.rb +93 -0
  29. data/cookbooks/jruby/attributes/default.rb +2 -0
  30. data/cookbooks/jruby/recipes/default.rb +24 -0
  31. data/cookbooks/server/recipes/default.rb +9 -0
  32. data/cookbooks/server/templates/default/server.sh.erb +27 -0
  33. data/cookbooks/vagrant_main/recipes/default.rb +4 -0
  34. data/engineyard-visualvm-java.gemspec +47 -0
  35. data/engineyard-visualvm.gemspec +43 -0
  36. data/engineyard-visualvm.gemspec.in +35 -0
  37. data/ext/org/jruby/ext/jmx/Agent.java +169 -0
  38. data/ext/org/jruby/ext/jmx/JavaHome.java +7 -0
  39. data/ext/org/jruby/ext/jmx/RMIServerSocketFactoryImpl.java +37 -0
  40. data/lib/engineyard-visualvm.rb +8 -0
  41. data/lib/engineyard-visualvm/agent.jar +0 -0
  42. data/lib/engineyard-visualvm/cli.rb +225 -0
  43. data/lib/engineyard-visualvm/version.rb +11 -0
  44. data/spec/engineyard-visualvm_spec.rb +202 -0
  45. data/spec/spec_helper.rb +49 -0
  46. metadata +157 -0
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ /.vagrant
@@ -0,0 +1,22 @@
1
+ 2011-12-13 Nick Sieger <nick@nicksieger.com>
2
+
3
+ * (Changes): Release 0.5.2
4
+
5
+ * lib/engineyard-visualvm/cli.rb (EngineYard::VisualVM::Helpers#fetch_public_ip):
6
+ Use public hostname from environment's single instance
7
+
8
+ * lib/engineyard-visualvm/cli.rb (EngineYard::VisualVM::CLI#start):
9
+ Ensure host is in known_hosts file before launching visual vm
10
+
11
+ 2011-12-08 Nick Sieger <nick@nicksieger.com>
12
+
13
+ * (Changes): Release 0.5.1
14
+
15
+ * lib/engineyard-visualvm/cli.rb (EngineYard::VisualVM::Helpers):
16
+ Make #options method available if needed when Helpers is included
17
+ into an arbitrary class.
18
+
19
+ 2011-12-02 Nick Sieger <nick@nicksieger.com>
20
+
21
+ * (Changes): Initial release (0.5.0)
22
+
data/Gemfile ADDED
@@ -0,0 +1,26 @@
1
+ #--
2
+ # Copyright (c) 2011 Engine Yard, Inc.
3
+ # See the file LICENSE.txt included with the distribution for
4
+ # software license details.
5
+ #++
6
+
7
+ source "http://rubygems.org"
8
+
9
+ group :development do
10
+ gem "vagrant"
11
+ gem "chef"
12
+
13
+ gem "jmx", :platform => :jruby
14
+ end
15
+
16
+ gemspec_in = Dir['*.gemspec.in'].first
17
+ gemspec_ruby = gemspec_in.sub(/\.gemspec\.in/, '')
18
+ gemspec_java = gemspec_ruby + '-java'
19
+
20
+ platforms :jruby do
21
+ gemspec :name => gemspec_java
22
+ end
23
+
24
+ platforms :ruby do
25
+ gemspec :name => gemspec_ruby
26
+ end
@@ -0,0 +1,23 @@
1
+ engineyard-visualvm is provided under the terms of the MIT license.
2
+
3
+ engineyard-visualvm (c) 2011 Engine Yard, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation files
7
+ (the "Software"), to deal in the Software without restriction,
8
+ including without limitation the rights to use, copy, modify, merge,
9
+ publish, distribute, sublicense, and/or sell copies of the Software,
10
+ and to permit persons to whom the Software is furnished to do so,
11
+ subject to 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
20
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
@@ -0,0 +1,104 @@
1
+ # engineyard-visualvm
2
+
3
+ `engineyard-visualvm` is a command-line utility for use with JRuby and
4
+ Engine Yard Cloud that makes it easy to connect Visual VM on a desktop
5
+ to a running JRuby or Java process in EY Cloud.
6
+
7
+ ## Usage
8
+
9
+ To start Visual VM on your local machine to an already-running process:
10
+
11
+ # Connect by EY Cloud environment and account
12
+ $ ey-visualvm start --environment=jruby --account=example
13
+
14
+ (If you need to see a list of available environments and their
15
+ associated accounts, use the `ey environments` command from the
16
+ [engineyard](/engineyard/engineyard) gem.)
17
+
18
+ You can also use the `engineyard-visualvm` gem to connect Visual VM to
19
+ any host where you have an available ssh connection.
20
+
21
+ # Connect by hostname:
22
+ $ ey-visualvm start --host=deploy@example.com
23
+
24
+ To connect to a server, the server must be booted with some additional
25
+ JVM arguments. These can be generated on the server side with:
26
+
27
+ $ ey-visualvm jvmargs
28
+ -Dorg.jruby.ext.jmx.agent.port=5900 -javaagent:/path/to/engineyard-visualvm/agent.jar
29
+
30
+ The server JVM binds to the loopback interface and listens on port
31
+ 5900 by default. If you want to use a different interface and/or port
32
+ than the default, pass `--host=<host-or-ip>` or `--port=<port>` to
33
+ `ey-visualvm jvmargs`.
34
+
35
+ ## Acceptance Test
36
+
37
+ To verify that a JMX connection to a server can be established, we can
38
+ use Vagrant and Chef to bootstrap a VM, start a JRuby process with JMX
39
+ enabled, create an ssh tunnel to the Vagrant box, and use the `jmx`
40
+ gem to connect to it from Ruby code. The code for this looks like
41
+ this:
42
+
43
+ ```ruby
44
+ require 'childprocess'
45
+ require 'jmx'
46
+
47
+ sh "vagrant ssh_config > ssh_config.tmp"
48
+ sh "vagrant up"
49
+ at_exit { sh "vagrant halt"; rm_f "ssh_config.tmp" }
50
+
51
+ @host, @port = 'localhost', 5900
52
+
53
+ ssh = ChildProcess.build("ssh", "-NL", "#{@port}:#{@host}:#{@port}", "-F", "ssh_config.tmp", "default")
54
+ ssh.start
55
+ at_exit { ssh.stop }
56
+
57
+ require 'engineyard-visualvm'
58
+ include EngineYard::VisualVM::Helpers
59
+ server = JMX::MBeanServer.new jmx_service_url
60
+
61
+ runtime_config_name = server.query_names('org.jruby:type=Runtime,name=*,service=Config').to_a.first
62
+ puts "Found runtime #{runtime_config_name}"
63
+ runtime_config = server[runtime_config_name]
64
+ puts "Runtime version: #{runtime_config['VersionString']}"
65
+ puts "OK"
66
+ ```
67
+
68
+ To try it yourself, do the following:
69
+
70
+ # Ensure you have vagrant and jmx installed
71
+ $ bundle install
72
+
73
+ # Run the acceptance test
74
+ $ rake acceptance
75
+ vagrant ssh_config > ssh_config.tmp
76
+ vagrant up
77
+ # ... bunch of output as the VM boots and Chef runs...
78
+ [default] [Tue, 22 Nov 2011 19:52:41 -0800] INFO: execute[start server] ran successfully
79
+ [Tue, 22 Nov 2011 19:52:41 -0800] INFO: Chef Run complete in 35.157236 seconds
80
+ [Tue, 22 Nov 2011 19:52:41 -0800] INFO: Running report handlers
81
+ [Tue, 22 Nov 2011 19:52:41 -0800] INFO: Report handlers complete
82
+ : stdout
83
+ Found runtime org.jruby:type=Runtime,name=25292276,service=Config
84
+ Runtime version: jruby 1.6.5 (ruby-1.8.7-p330) (2011-10-25 9dcd388) (Java HotSpot(TM) Client VM 1.6.0_26) [linux-i386-java]
85
+ OK
86
+ vagrant halt
87
+ [default] Attempting graceful shutdown of linux...
88
+ rm -f ssh_config.tmp
89
+
90
+ ## Bits and Pieces
91
+
92
+ - Gem: `gem install engineyard-visualvm`
93
+ - Source: https://github.com/engineyard/engineyard-visualvm
94
+ - License: MIT; see LICENSE.txt for details.
95
+
96
+ ## TODO
97
+
98
+ - Prompt for a JVM to connect to if more than one JVM process is
99
+ running on the server
100
+ - Prompt for an instance to connect to if the environment has multiple
101
+ instances
102
+ - Data collected by `jstatd` is not yet supported, so things like the
103
+ Visual GC tab are not supported yet.
104
+ - Additional utilities to make use of the JMX connection remotely
@@ -0,0 +1,124 @@
1
+ #--
2
+ # Copyright (c) 2011 Engine Yard, Inc.
3
+ # See the file LICENSE.txt included with the distribution for
4
+ # software license details.
5
+ #++
6
+
7
+ require "rake/clean"
8
+
9
+ desc "Compile and jar the agent extension class"
10
+ begin
11
+ require 'ant'
12
+ jar_file = "lib/engineyard-visualvm/agent.jar"
13
+ directory "pkg/classes"
14
+ CLEAN << "pkg"
15
+
16
+ file jar_file => FileList['ext/**/*.java', 'pkg/classes'] do
17
+ rm_rf FileList['pkg/classes/**/*']
18
+ ant.javac :srcdir => "ext", :destdir => "pkg/classes",
19
+ :source => "1.5", :target => "1.5", :debug => true,
20
+ :classpath => "${java.class.path}:${sun.boot.class.path}",
21
+ :includeantRuntime => false
22
+
23
+ ant.jar :basedir => "pkg/classes", :destfile => jar_file, :includes => "**/*.class" do
24
+ manifest do
25
+ attribute :name => "Premain-Class", :value => "org.jruby.ext.jmx.Agent"
26
+ end
27
+ end
28
+ end
29
+
30
+ task :jar => jar_file
31
+ rescue LoadError
32
+ task :jar do
33
+ puts "Run 'jar' with JRuby to re-compile the agent extension class"
34
+ end
35
+ end
36
+
37
+ # Make sure jar gets compiled before the gem is built
38
+ task :build => :jar
39
+
40
+ task :default => :spec
41
+
42
+ require 'rspec/core/rake_task'
43
+ RSpec::Core::RakeTask.new
44
+
45
+ task :spec => :jar
46
+
47
+ ## Bundler tasks
48
+ gemspec_in = FileList['*.gemspec.in'].first
49
+ gemspec = gemspec_in.sub(/\.in/, '')
50
+ gemspec_java = gemspec.sub(/\.gemspec/, '-java.gemspec')
51
+ write_gemspecs = lambda {
52
+ File.open(gemspec, 'w') {|f| f << eval(File.read(gemspec_in)).to_ruby }
53
+ File.open(gemspec_java, 'w') {|f| use_jruby = true; f << eval(File.read(gemspec_in)).to_ruby }
54
+ }
55
+ write_gemspecs.call unless File.exist?(gemspec) && File.exist?(gemspec_java)
56
+
57
+ task :update_gemspecs do
58
+ write_gemspecs.call
59
+ end
60
+ task :build => :update_gemspecs
61
+ task :install => :update_gemspecs
62
+ task :release => :update_gemspecs
63
+
64
+ require "bundler/gem_helper"
65
+
66
+ Bundler::GemHelper.install_tasks(:name => gemspec.sub('.gemspec', ''))
67
+ namespace :java do
68
+ gh = Bundler::GemHelper.new(Dir.pwd, gemspec_java.sub('.gemspec', ''))
69
+ # These are no-ops since we will have already tagged and pushed
70
+ def gh.guard_already_tagged; end
71
+ def gh.tag_version; yield if block_given?; end
72
+ def gh.git_push; end
73
+ gh.install
74
+ end
75
+
76
+ task :build do
77
+ Rake::Task["java:build"].invoke
78
+ end
79
+ task :release do
80
+ Rake::Task["java:release"].invoke
81
+ end
82
+
83
+ # Override push to use engineyard key
84
+ class Bundler::GemHelper
85
+ def rubygem_push(path)
86
+ if Gem.configuration.api_keys.key? :engineyard
87
+ sh("gem push -k engineyard '#{path}'")
88
+ Bundler.ui.confirm "Pushed #{name} #{version} to rubygems.org"
89
+ else
90
+ raise ":engineyard key not set in ~/.gem/credentials"
91
+ end
92
+ end
93
+ end
94
+
95
+ ## Acceptance task
96
+ begin
97
+ require 'childprocess'
98
+ require 'jmx'
99
+ task :acceptance => :build do
100
+ sh "vagrant ssh_config > ssh_config.tmp"
101
+ sh "vagrant up"
102
+ at_exit { sh "vagrant halt"; rm_f "ssh_config.tmp" }
103
+
104
+ @host, @port = 'localhost', 5900
105
+
106
+ ssh = ChildProcess.build("ssh", "-NL", "#{@port}:#{@host}:#{@port}", "-F", "ssh_config.tmp", "default")
107
+ ssh.start
108
+ at_exit { ssh.stop }
109
+
110
+ require 'engineyard-visualvm'
111
+ include EngineYard::VisualVM::Helpers
112
+ server = JMX::MBeanServer.new jmx_service_url
113
+
114
+ runtime_config_name = server.query_names('org.jruby:type=Runtime,name=*,service=Config').to_a.first
115
+ puts "Found runtime #{runtime_config_name}"
116
+ runtime_config = server[runtime_config_name]
117
+ puts "Runtime version: #{runtime_config['VersionString']}"
118
+ puts "OK"
119
+ end
120
+ rescue LoadError
121
+ task :acceptance do
122
+ fail "Run 'acceptance' with JRuby to actually run the test"
123
+ end
124
+ end
@@ -0,0 +1,94 @@
1
+ Vagrant::Config.run do |config|
2
+ # All Vagrant configuration is done here. The most common configuration
3
+ # options are documented and commented below. For a complete reference,
4
+ # please see the online documentation at vagrantup.com.
5
+
6
+ # Every Vagrant virtual environment requires a box to build off of.
7
+ config.vm.box = "base"
8
+
9
+ # The url from where the 'config.vm.box' box will be fetched if it
10
+ # doesn't already exist on the user's system.
11
+ # config.vm.box_url = "http://domain.com/path/to/above.box"
12
+
13
+ # Boot with a GUI so you can see the screen. (Default is headless)
14
+ # config.vm.boot_mode = :gui
15
+
16
+ # Assign this VM to a host only network IP, allowing you to access it
17
+ # via the IP.
18
+ config.vm.network "33.33.33.10"
19
+
20
+ # Forward a port from the guest to the host, which allows for outside
21
+ # computers to access the VM, whereas host only networking does not.
22
+ # config.vm.forward_port "http", 80, 8080
23
+
24
+ # Share an additional folder to the guest VM. The first argument is
25
+ # an identifier, the second is the path on the guest to mount the
26
+ # folder, and the third is the path on the host to the actual folder.
27
+ # config.vm.share_folder "v-data", "/vagrant_data", "../data"
28
+
29
+ # Enable provisioning with Puppet stand alone. Puppet manifests
30
+ # are contained in a directory path relative to this Vagrantfile.
31
+ # You will need to create the manifests directory and a manifest in
32
+ # the file base.pp in the manifests_path directory.
33
+ #
34
+ # An example Puppet manifest to provision the message of the day:
35
+ #
36
+ # # group { "puppet":
37
+ # # ensure => "present",
38
+ # # }
39
+ # #
40
+ # # File { owner => 0, group => 0, mode => 0644 }
41
+ # #
42
+ # # file { '/etc/motd':
43
+ # # content => "Welcome to your Vagrant-built virtual machine!
44
+ # # Managed by Puppet.\n"
45
+ # # }
46
+ #
47
+ # config.vm.provision :puppet do |puppet|
48
+ # puppet.manifests_path = "manifests"
49
+ # puppet.manifest_file = "base.pp"
50
+ # end
51
+
52
+ # Enable provisioning with chef solo, specifying a cookbooks path (relative
53
+ # to this Vagrantfile), and adding some recipes and/or roles.
54
+ #
55
+ # config.vm.provision :chef_solo do |chef|
56
+ # chef.cookbooks_path = "cookbooks"
57
+ # chef.add_recipe "mysql"
58
+ # chef.add_role "web"
59
+ #
60
+ # # You may also specify custom JSON attributes:
61
+ # chef.json = { :mysql_password => "foo" }
62
+ # end
63
+ config.vm.provision :chef_solo do |chef|
64
+ chef.cookbooks_path = "cookbooks"
65
+ chef.add_recipe("vagrant_main")
66
+ end
67
+
68
+ # Enable provisioning with chef server, specifying the chef server URL,
69
+ # and the path to the validation key (relative to this Vagrantfile).
70
+ #
71
+ # The Opscode Platform uses HTTPS. Substitute your organization for
72
+ # ORGNAME in the URL and validation key.
73
+ #
74
+ # If you have your own Chef Server, use the appropriate URL, which may be
75
+ # HTTP instead of HTTPS depending on your configuration. Also change the
76
+ # validation key to validation.pem.
77
+ #
78
+ # config.vm.provision :chef_client do |chef|
79
+ # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
80
+ # chef.validation_key_path = "ORGNAME-validator.pem"
81
+ # end
82
+ #
83
+ # If you're using the Opscode platform, your validator client is
84
+ # ORGNAME-validator, replacing ORGNAME with your organization name.
85
+ #
86
+ # IF you have your own Chef Server, the default validation client name is
87
+ # chef-validator, unless you changed the configuration.
88
+ #
89
+ # chef.validation_client_name = "ORGNAME-validator"
90
+ end
91
+
92
+ # Local Variables:
93
+ # mode: ruby
94
+ # End:
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2011 Engine Yard, Inc.
4
+ # See the file LICENSE.txt included with the distribution for
5
+ # software license details.
6
+
7
+ require 'engineyard-visualvm'
8
+
9
+ EngineYard::VisualVM::CLI.start
@@ -0,0 +1,122 @@
1
+ Description
2
+ ===========
3
+
4
+ This cookbook includes recipes to execute apt-get update to ensure the local APT package cache is up to date or manage apt-cacher and cacher clients. It also includes a LWRP for managing APT repositories in /etc/apt/sources.list.d.
5
+
6
+ Recipes
7
+ =======
8
+
9
+ default
10
+ -------
11
+
12
+ This recipe installs the `update-notifier-common` package to provide the timestamp file used to only run `apt-get update` if the cache is less than one day old.
13
+
14
+ This recipe should appear first in the run list of Debian or Ubuntu nodes to ensure that the package cache is up to date before managing any `package` resources with Chef.
15
+
16
+ This recipe also sets up a local cache directory for preseeding packages.
17
+
18
+ cacher
19
+ ------
20
+
21
+ Installs the apt-cacher package and service so the system can provide APT caching. You can check the usage report at http://{hostname}:3142/report. The cacher recipe includes the `cacher-client` recipe, so it helps seed itself.
22
+
23
+ cacher-client
24
+ -------------
25
+ Configures the node to use the apt-cacher server as a client.
26
+
27
+ Resources/Providers
28
+ ===================
29
+
30
+ This LWRP provides an easy way to manage additional APT repositories. Adding a new repository will notify running the `execute[apt-get-update]` resource.
31
+
32
+ # Actions
33
+
34
+ - :add: creates a repository file and builds the repository listing
35
+ - :remove: removes the repository file
36
+
37
+ # Attribute Parameters
38
+
39
+ - repo_name: name attribute. The name of the channel to discover
40
+ - uri: the base of the Debian distribution
41
+ - distribution: this is usually your release's codename...ie something like `karmic`, `lucid` or `maverick`
42
+ - components: package groupings..when it doubt use `main`
43
+ - deb_src: whether or not to add the repository as a source repo as well
44
+ - key_server: the GPG keyserver where the key for the repo should be retrieved
45
+ - key: if a `key_server` is provided, this is assumed to be the fingerprint, otherwise it is the URI to the GPG key for the repo
46
+
47
+ # Examples
48
+
49
+ # add the Zenoss repo
50
+ apt_repository "zenoss" do
51
+ uri "http://dev.zenoss.org/deb"
52
+ components ["main","stable"]
53
+ action :add
54
+ end
55
+
56
+ # add the Nginx PPA; grab key from keyserver
57
+ apt_repository "nginx-php" do
58
+ uri "http://ppa.launchpad.net/nginx/php5/ubuntu"
59
+ distribution node['lsb']['codename']
60
+ components ["main"]
61
+ keyserver "keyserver.ubuntu.com"
62
+ key "C300EE8C"
63
+ action :add
64
+ end
65
+
66
+ # add the Cloudkick Repo
67
+ apt_repository "cloudkick" do
68
+ uri "http://packages.cloudkick.com/ubuntu"
69
+ distribution node['lsb']['codename']
70
+ components ["main"]
71
+ key "http://packages.cloudkick.com/cloudkick.packages.key"
72
+ action :add
73
+ end
74
+
75
+ # remove Zenoss repo
76
+ apt_repository "zenoss" do
77
+ action :remove
78
+ end
79
+
80
+ Usage
81
+ =====
82
+
83
+ Put `recipe[apt]` first in the run list. If you have other recipes that you want to use to configure how apt behaves, like new sources, notify the execute resource to run, e.g.:
84
+
85
+ template "/etc/apt/sources.list.d/my_apt_sources.list" do
86
+ notifies :run, resources(:execute => "apt-get update"), :immediately
87
+ end
88
+
89
+ The above will run during execution phase since it is a normal template resource, and should appear before other package resources that need the sources in the template.
90
+
91
+ Put `recipe[apt::cacher]` in the run_list for a server to provide APT caching and add `recipe[apt::cacher-client]` on the rest of the Debian-based nodes to take advantage of the caching server.
92
+
93
+ Changes
94
+ =======
95
+
96
+ ## v1.2.0:
97
+
98
+ * COOK-136: Limit apt-get update to one run per day unless notified.
99
+ * COOK-471: ignore failure on apt-get update
100
+ * COOK-533: add support for deb and `deb_src` repos with `apt_repository`
101
+
102
+ License and Author
103
+ ==================
104
+
105
+ Author:: Joshua Timberman (<joshua@opscode.com>)
106
+ Author:: Matt Ray (<matt@opscode.com>)
107
+ Author:: Seth Chisamore (<schisamo@opscode.com>)
108
+
109
+ Copyright 2009-2011 Opscode, Inc.
110
+
111
+ Licensed under the Apache License, Version 2.0 (the "License");
112
+ you may not use this file except in compliance with the License.
113
+ You may obtain a copy of the License at
114
+
115
+ http://www.apache.org/licenses/LICENSE-2.0
116
+
117
+ Unless required by applicable law or agreed to in writing, software
118
+ distributed under the License is distributed on an "AS IS" BASIS,
119
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
120
+ See the License for the specific language governing permissions and
121
+ limitations under the License.
122
+