diff --git a/.gitignore b/.gitignore index 32c4421..45b891c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,15 @@ -.project -.buildpath \ No newline at end of file +.vagrant +Berksfile.lock +*~ +*# +.#* +\#*# +.*.sw[a-z] +*.un~ +/cookbooks + +# Bundler +Gemfile.lock +bin/* +.bundle/* + diff --git a/.kitchen.yml b/.kitchen.yml new file mode 100644 index 0000000..8e31207 --- /dev/null +++ b/.kitchen.yml @@ -0,0 +1,15 @@ +--- +driver: + name: vagrant + +provisioner: + name: chef_solo + +platforms: + - name: ubuntu-12.04 + - name: centos-6.4 + +suites: + - name: default + run_list: + attributes: diff --git a/Berksfile b/Berksfile new file mode 100644 index 0000000..c4bb297 --- /dev/null +++ b/Berksfile @@ -0,0 +1,3 @@ +site :opscode + +metadata diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..3017623 --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gem 'berkshelf' diff --git a/README.md b/README.md index 9da9c23..d5a54ac 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,9 @@ -# DESCRIPTION: +Warning +======= -This cookbook basically translates the install instructions from http://docs.codehaus.org/display/SONAR/Install+Sonar#InstallSonar-Server into chef DSL. +This cookbook is still on the state of Sonar 2.14 and not very generic. We use it for [metrics.typo3.org](http://metrics.typo3.org) were it does what it should. -# REQUIREMENTS: +Description +=========== -* `java` + `jdk` -* A database cookbook like `mysql` if you like to run sonar in production. -The built in derby database is not recommended for production. - -# ATTRIBUTES: - -See `attributes/default.rb` for details. - -# USAGE: - -The cookbook installs sonar with derby database (default). -Inlcude a `proxy_*` recipe to your `run_list` to access sonar over a proxy server. - -# Todos - -* Implement `dir` attribute to make installation path more flexible -* Implement different Database backends like MySql -* Implement plugin recipes eg. http://docs.codehaus.org/display/SONAR/PHP+Plugin - Download jars to plugin folder, restart Sonar -* Create database with mysql LWRP -
-	mysql_database "sonar" do
-	  host "localhost"
-	  username "root"
-	  password node[:mysql][:server_root_password]
-	  database "sonar"
-	  action :create_db
-	end
-
-* Set allow / deny patterns with attributes for web access -
-	default['sonar']['web_deny']               = []
-	default['sonar']['web_allow']              = []
-
+This Chef cookbook installs Sonar(Qube). \ No newline at end of file diff --git a/Thorfile b/Thorfile new file mode 100644 index 0000000..cb1aeae --- /dev/null +++ b/Thorfile @@ -0,0 +1,5 @@ +# encoding: utf-8 + +require 'bundler' +require 'bundler/setup' +require 'berkshelf/thor' diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..133d52e --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,85 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +Vagrant.configure("2") do |config| + # All Vagrant configuration is done here. The most common configuration + # options are documented and commented below. For a complete reference, + # please see the online documentation at vagrantup.com. + + config.vm.hostname = "sonar-berkshelf" + + # Every Vagrant virtual environment requires a box to build off of. + config.vm.box = "opscode-debian-7.2" + + # The url from where the 'config.vm.box' box will be fetched if it + # doesn't already exist on the user's system. + config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_debian-7.2.0_chef-provisionerless.box" + + # Assign this VM to a host-only network IP, allowing you to access it + # via the IP. Host-only networks can talk to the host machine as well as + # any other machines on the same network, but cannot be accessed (through this + # network interface) by any external networks. + config.vm.network :private_network, ip: "33.33.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + + # config.vm.network :public_network + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + # config.vm.provider :virtualbox do |vb| + # # Don't boot with headless mode + # vb.gui = true + # + # # Use VBoxManage to customize the VM. For example to change memory: + # vb.customize ["modifyvm", :id, "--memory", "1024"] + # end + # + # View the documentation for the provider you're using for more + # information on available options. + + # The path to the Berksfile to use with Vagrant Berkshelf + # config.berkshelf.berksfile_path = "./Berksfile" + + # Enabling the Berkshelf plugin. To enable this globally, add this configuration + # option to your ~/.vagrant.d/Vagrantfile file + config.berkshelf.enabled = true + + # An array of symbols representing groups of cookbook described in the Vagrantfile + # to exclusively install and copy to Vagrant's shelf. + # config.berkshelf.only = [] + + # An array of symbols representing groups of cookbook described in the Vagrantfile + # to skip installing and copying to Vagrant's shelf. + # config.berkshelf.except = [] + + config.omnibus.chef_version = :latest + + config.vm.provision :chef_solo do |chef| + chef.json = { + :mysql => { + :server_root_password => 'rootpass', + :server_debian_password => 'debpass', + :server_repl_password => 'replpass' + } + } + + chef.run_list = [ + "recipe[sonar::default]" + ] + end +end diff --git a/attributes/default.rb b/attributes/default.rb index d802e6d..9f20245 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -1,8 +1,7 @@ # General settings default['sonar']['dir'] = "/opt/sonar" -default['sonar']['version'] = "2.11" -default['sonar']['checksum'] = "9d05e25ca79c33d673004444d89c8770" -default['sonar']['os_kernel'] = "linux-x86-32" +default['sonar']['version'] = "2.14" +default['sonar']['os_kernel'] = "linux-x86-64" default['sonar']['mirror'] = "http://dist.sonar.codehaus.org" # Web settings diff --git a/chefignore b/chefignore new file mode 100644 index 0000000..a6de142 --- /dev/null +++ b/chefignore @@ -0,0 +1,96 @@ +# Put files/directories that should be ignored in this file when uploading +# or sharing to the community site. +# Lines that start with '# ' are comments. + +# OS generated files # +###################### +.DS_Store +Icon? +nohup.out +ehthumbs.db +Thumbs.db + +# SASS # +######## +.sass-cache + +# EDITORS # +########### +\#* +.#* +*~ +*.sw[a-z] +*.bak +REVISION +TAGS* +tmtags +*_flymake.* +*_flymake +*.tmproj +.project +.settings +mkmf.log + +## COMPILED ## +############## +a.out +*.o +*.pyc +*.so +*.com +*.class +*.dll +*.exe +*/rdoc/ + +# Testing # +########### +.watchr +.rspec +spec/* +spec/fixtures/* +test/* +features/* +Guardfile +Procfile + +# SCM # +####### +.git +*/.git +.gitignore +.gitmodules +.gitconfig +.gitattributes +.svn +*/.bzr/* +*/.hg/* +*/.svn/* + +# Berkshelf # +############# +Berksfile +Berksfile.lock +cookbooks/* +tmp + +# Cookbooks # +############# +CONTRIBUTING +CHANGELOG* + +# Strainer # +############ +Colanderfile +Strainerfile +.colander +.strainer + +# Vagrant # +########### +.vagrant +Vagrantfile + +# Travis # +########## +.travis.yml diff --git a/libraries/helper.rb b/libraries/helper.rb new file mode 100644 index 0000000..58a8db7 --- /dev/null +++ b/libraries/helper.rb @@ -0,0 +1,56 @@ +# +# Cookbook Name:: sonar +# Library:: helper +# +# Copyright 2014, Steffen Gebert / TYPO3 Association +# +# Based on the jenkins cookbook: +# Author:: Seth Chisamore +# Copyright 2012, Opscode, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/mixin/shell_out' +require 'chef/rest' + +# Helper library for testing Jenkins responses +module SonarHelper + extend Chef::Mixin::ShellOut + + def self.service_listening?(port) + netstat_command = 'netstat -lnt' + cmd = shell_out!(netstat_command) + Chef::Log.debug("`#{netstat_command}` returned: \n\n #{cmd.stdout}") + cmd.stdout.each_line.select do |l| + l.split[3] =~ /#{port}/ + end.any? + end + + def self.endpoint_responding?(url) + response = Chef::REST::RESTRequest.new(:GET, url, nil).call + if response.kind_of?(Net::HTTPSuccess) || + response.kind_of?(Net::HTTPOK) || + response.kind_of?(Net::HTTPRedirection) || + response.kind_of?(Net::HTTPForbidden) + Chef::Log.debug("GET to #{url} successful") + return true + else + Chef::Log.debug("GET to #{url} returned #{response.code} / #{response.class}") + return false + end + rescue EOFError, Errno::ECONNREFUSED + Chef::Log.debug("GET to #{url} failed with connection refused") + return false + end +end diff --git a/metadata.rb b/metadata.rb index 838ec8e..cbf9e6c 100644 --- a/metadata.rb +++ b/metadata.rb @@ -3,7 +3,7 @@ license "Apache 2.0" description "Installs/Configures sonar" long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) -version "0.0.4" +version "0.0.6" recipe "sonar", "Includes the recipe to download and configure a sonar server" recipe "sonar::database_mysql", "Includes the recipe to install MySql-Server and create a database for sonar" recipe "sonar::proxy_apache", "Includes the recipe to install Apache-Webserver and proxy modules to access sonar. Creates a host for sonar." @@ -13,7 +13,7 @@ supports os end -%w{ java }.each do |cb| +%w{ java ark database mysql nginx }.each do |cb| depends cb end diff --git a/providers/plugin.rb b/providers/plugin.rb new file mode 100644 index 0000000..b1f5714 --- /dev/null +++ b/providers/plugin.rb @@ -0,0 +1,92 @@ +# +# Cookbook Name:: sonar +# Provider:: plugin +# +# Copyright 2014, Steffen Gebert / TYPO3 Association +# +# Based on jenkins cookbook: +# Copyright 2013, Opscode, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def whyrun_supported? + true +end + + +action :install do + unless plugin_exists? + converge_by("Installing sonar plugin #{@new_resource.name} version #{@new_resource.version}") do + do_install_plugin + end + else + Chef::Log.debug "#{@new_resource.name} already exists" + end +end + +action :remove do + if plugin_exists? + converge_by("remove #{@new_resource.name}") do + do_remove_plugin + end + else + Chef::Log.debug "#{@new_resource.name} doesn't exist" + end +end + +private + +def plugins_dir + ::File.join(node['sonar']['dir'], 'extensions/plugins') +end + +def plugin_file_name + @new_resource.name + '-' + @new_resource.version + '.jar' +end + +def plugin_file_path + ::File.join(plugins_dir, plugin_file_name) +end + +def plugin_exists? + ::File.exists?(plugin_file_path) +end + +def do_install_plugin + plugin_url = @new_resource.url + + remote_file plugin_file_path do + source plugin_url + backup false + action :create + notifies :restart, 'service[sonar]' + end + +end + +def do_remove_plugin + file plugin_file_path do + action :delete + backup false + notifies :restart, 'service[sonar]' + notifies :create, 'ruby_block[block_sonar_until_operational]' + end + + directory plugin_dir_path do + action :delete + recursive true + notifies :restart, 'service[sonar]' + notifies :create, 'ruby_block[block_sonar_until_operational]' + end +end diff --git a/recipes/database_mysql.rb b/recipes/database_mysql.rb index ba193ab..db92c54 100644 --- a/recipes/database_mysql.rb +++ b/recipes/database_mysql.rb @@ -1,17 +1,33 @@ -include_recipe "mysql::server" +include_recipe "database::mysql" -# Setup sonar user -grants_path = "/opt/sonar/extras/database/mysql/create_database.sql" +mysql_connection_info = { + :host => 'localhost', + :username => 'root', + :password => node['mysql']['server_root_password'] +} -template grants_path do - source "create_mysql_database.sql.erb" - owner "root" - group "root" - mode "0600" - action :create - notifies :restart, resources(:service => "sonar") +mysql_database "sonar" do + connection mysql_connection_info + collation "utf8_general_ci" + encoding "utf8" end -execute "mysql-install-application-privileges" do - command "/usr/bin/mysql -u root #{node[:mysql][:server_root_password].empty? ? '' : '-p' }#{node[:mysql][:server_root_password]} < #{grants_path}" +mysql_database_user "sonar" do + connection mysql_connection_info + password node['sonar']['jdbc_password'] + action :create + notifies :grant, "mysql_database_user[sonar]" end + +mysql_database_user "sonar-grant" do + connection mysql_connection_info + database_name "sonar" + action :nothing # should be notified with :grant + notifies :query, "mysql_database[flush privileges]" +end + +mysql_database 'flush privileges' do + connection mysql_connection_info + sql 'flush privileges' + action :nothing # should be notified with #query +end \ No newline at end of file diff --git a/recipes/default.rb b/recipes/default.rb index 27f19a5..372b149 100644 --- a/recipes/default.rb +++ b/recipes/default.rb @@ -17,23 +17,15 @@ # limitations under the License. # +include_recipe "ark" include_recipe "java" -package "unzip" - -remote_file "/opt/sonar-#{node['sonar']['version']}.zip" do - source "#{node['sonar']['mirror']}/sonar-#{node['sonar']['version']}.zip" - mode "0644" - checksum "#{node['sonar']['checksum']}" - not_if { ::File.exists?("/opt/sonar-#{node['sonar']['version']}.zip") } -end - -execute "unzip /opt/sonar-#{node['sonar']['version']}.zip -d /opt/" do - not_if { ::File.directory?("/opt/sonar-#{node['sonar']['version']}/") } -end - -link "/opt/sonar" do - to "/opt/sonar-#{node['sonar']['version']}" +ark "sonar" do + prefix_home "/opt" + prefix_root "/opt" + version node['sonar']['version'] + url "#{node['sonar']['mirror']}/sonar-#{node['sonar']['version']}.zip" + action :install end service "sonar" do @@ -53,7 +45,8 @@ variables( :options => node['sonar']['options'] ) - notifies :restart, resources(:service => "sonar") + notifies :restart, 'service[sonar]', :immediately + notifies :create, 'ruby_block[block_sonar_until_operational]', :immediately end template "wrapper.conf" do @@ -62,5 +55,29 @@ owner "root" group "root" mode 0644 - notifies :restart, resources(:service => "sonar") + notifies :restart, 'service[sonar]', :immediately + notifies :create, 'ruby_block[block_sonar_until_operational]', :immediately +end + +ruby_block 'block_sonar_until_operational' do + block do + Chef::Log.info "Waiting until Sonar is listening on port #{node['sonar']['web_port']}" + until SonarHelper.service_listening?(node['sonar']['web_port']) + sleep 1 + Chef::Log.debug('.') + end + + Chef::Log.info 'Waiting until the Sonar API is responding' + test_url = URI.parse("http://localhost:#{node['sonar']['web_port']}/api/server") + until SonarHelper.endpoint_responding?(test_url) + sleep 1 + Chef::Log.debug('.') + end + end + action :nothing +end + +log 'ensure_sonar_is_running' do + notifies :start, 'service[sonar]', :immediately + notifies :create, 'ruby_block[block_sonar_until_operational]', :immediately end diff --git a/resources/plugin.rb b/resources/plugin.rb new file mode 100644 index 0000000..17d7d93 --- /dev/null +++ b/resources/plugin.rb @@ -0,0 +1,27 @@ +# +# Cookbook Name:: sonar +# Resource:: plugin +# +# Copyright 2014, Steffen Gebert / TYPO3 Association +# +# Based on jenkins cookbook: +# Copyright 2013, Opscode, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +actions :install, :remove +default_action :install + +attribute :version, :kind_of => String +attribute :url, :kind_of => String \ No newline at end of file