Update cookbooks

This commit is contained in:
Greg Karékinian 2016-04-16 00:15:56 +02:00
parent 3854ab7232
commit c50b096c37
127 changed files with 1792 additions and 7431 deletions

10
Batali
View File

@ -5,7 +5,13 @@ Batali.define do
cookbook 'mediawiki',
git: 'https://github.com/67P/mediawiki-cookbook.git',
ref: 'master'
ref: 'nginx'
cookbook 'php-fpm',
git: 'https://github.com/67P/cookbook-php-fpm.git',
ref: 'ubuntu_systemd'
cookbook 'wordpress',
git: 'https://github.com/67P/wordpress-cookbook.git',
ref: 'relax_dependencies'
cookbook 'postfix'
cookbook 'unattended-upgrades'
cookbook 'application_nodejs',
@ -20,6 +26,7 @@ Batali.define do
git: 'https://github.com/phlipper/chef-redis.git',
ref: 'v0.5.6'
cookbook 'ufw'
cookbook 'firewall'
cookbook 'ssh_known_hosts'
cookbook 'nginx'
cookbook 'build-essential', '~> 2.2.4'
@ -29,6 +36,5 @@ Batali.define do
cookbook 'omnibus_updater', '~> 1.0.4'
cookbook 'timezone-ii'
cookbook 'nodejs', '~> 2.4.4'
cookbook 'wordpress'
end

View File

@ -2,43 +2,107 @@
"infrastructure": false,
"cookbook": [
{
"name": "mediawiki",
"name": "php-fpm",
"dependencies": [
[
"apache2",
"apt",
"> 0"
],
[
"php",
"> 0"
],
[
"mysql",
"> 0"
],
[
"database",
"> 0"
"yum",
">= 3.0"
]
],
"version": "0.1.0",
"version": "0.7.5",
"source": {
"url": "https://github.com/67P/mediawiki-cookbook.git",
"ref": "35e33e3d563987fa7c156def2d26654ecc4cb9a1",
"url": "https://github.com/67P/cookbook-php-fpm.git",
"ref": "00ae43a225cf23fd3ed937f27ab25aba8d812db9",
"type": "Batali::Source::Git",
"subdirectory": null
}
},
{
"name": "apache2",
"name": "apt",
"dependencies": [
],
"version": "3.1.0",
"version": "2.9.2",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/apache2/versions/3.1.0/download",
"version": "3.1.0"
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/apt/versions/2.9.2/download",
"version": "2.9.2"
}
},
{
"name": "yum",
"dependencies": [
],
"version": "3.10.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/yum/versions/3.10.0/download",
"version": "3.10.0"
}
},
{
"name": "wordpress",
"dependencies": [
[
"php",
"> 0"
],
[
"openssl",
"> 0"
],
[
"apache2",
">= 2.0.0"
],
[
"database",
">= 1.6.0"
],
[
"mysql",
">= 6.0"
],
[
"mysql2_chef_gem",
"~> 1.0.1"
],
[
"build-essential",
"> 0"
],
[
"iis",
">= 1.6.2"
],
[
"tar",
">= 0.3.1"
],
[
"nginx",
"~> 2.7.4"
],
[
"php-fpm",
"> 0"
],
[
"selinux",
"~> 0.7"
]
],
"version": "3.0.0",
"source": {
"url": "https://github.com/67P/wordpress-cookbook.git",
"ref": "bc6a108fcfb05c3fafd903bcf81ac33617e6cef9",
"type": "Batali::Source::Git",
"subdirectory": null
}
},
{
@ -131,11 +195,11 @@
">= 0.0.0"
]
],
"version": "6.1.2",
"version": "6.1.3",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/mysql/versions/6.1.2/download",
"version": "6.1.2"
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/mysql/versions/6.1.3/download",
"version": "6.1.3"
}
},
{
@ -153,18 +217,6 @@
"version": "0.1.21"
}
},
{
"name": "yum",
"dependencies": [
],
"version": "3.10.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/yum/versions/3.10.0/download",
"version": "3.10.0"
}
},
{
"name": "smf",
"dependencies": [
@ -249,6 +301,33 @@
"version": "4.1.6"
}
},
{
"name": "openssl",
"dependencies": [
[
"chef-sugar",
">= 3.1.1"
]
],
"version": "4.4.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/openssl/versions/4.4.0/download",
"version": "4.4.0"
}
},
{
"name": "apache2",
"dependencies": [
],
"version": "3.1.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/apache2/versions/3.1.0/download",
"version": "3.1.0"
}
},
{
"name": "database",
"dependencies": [
@ -288,30 +367,212 @@
}
},
{
"name": "apt",
"name": "mysql2_chef_gem",
"dependencies": [
[
"build-essential",
">= 0.0.0"
],
[
"mysql",
"~> 6.0"
],
[
"mariadb",
">= 0.0.0"
]
],
"version": "2.9.2",
"version": "1.0.2",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/apt/versions/2.9.2/download",
"version": "2.9.2"
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/mysql2_chef_gem/versions/1.0.2/download",
"version": "1.0.2"
}
},
{
"name": "openssl",
"name": "mariadb",
"dependencies": [
[
"chef-sugar",
">= 3.1.1"
"apt",
">= 0.0.0"
],
[
"yum",
">= 0.0.0"
],
[
"yum-epel",
">= 0.0.0"
]
],
"version": "4.4.0",
"version": "0.3.1",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/openssl/versions/4.4.0/download",
"version": "4.4.0"
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/mariadb/versions/0.3.1/download",
"version": "0.3.1"
}
},
{
"name": "tar",
"dependencies": [
],
"version": "0.7.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/tar/versions/0.7.0/download",
"version": "0.7.0"
}
},
{
"name": "nginx",
"dependencies": [
[
"apt",
"~> 2.2"
],
[
"bluepill",
"~> 2.3"
],
[
"build-essential",
"~> 2.0"
],
[
"ohai",
"~> 2.0"
],
[
"runit",
"~> 1.2"
],
[
"yum-epel",
"~> 0.3"
]
],
"version": "2.7.6",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/nginx/versions/2.7.6/download",
"version": "2.7.6"
}
},
{
"name": "bluepill",
"dependencies": [
[
"rsyslog",
"~> 2.0"
]
],
"version": "2.4.1",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/bluepill/versions/2.4.1/download",
"version": "2.4.1"
}
},
{
"name": "rsyslog",
"dependencies": [
],
"version": "2.2.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/rsyslog/versions/2.2.0/download",
"version": "2.2.0"
}
},
{
"name": "ohai",
"dependencies": [
],
"version": "2.1.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/ohai/versions/2.1.0/download",
"version": "2.1.0"
}
},
{
"name": "runit",
"dependencies": [
[
"packagecloud",
">= 0.0.0"
]
],
"version": "1.7.6",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/runit/versions/1.7.6/download",
"version": "1.7.6"
}
},
{
"name": "packagecloud",
"dependencies": [
],
"version": "0.2.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/packagecloud/versions/0.2.0/download",
"version": "0.2.0"
}
},
{
"name": "selinux",
"dependencies": [
],
"version": "0.9.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/selinux/versions/0.9.0/download",
"version": "0.9.0"
}
},
{
"name": "mediawiki",
"dependencies": [
[
"apache2",
"> 0"
],
[
"php",
"> 0"
],
[
"mysql",
"> 0"
],
[
"database",
"> 0"
],
[
"nginx",
"> 0"
],
[
"mysql2_chef_gem",
"> 0"
],
[
"php-fpm",
"> 0"
]
],
"version": "0.2.0",
"source": {
"type": "Batali::Source::Path",
"path": "/Users/kare/code/kosmos/cookbooks/mediawiki-cookbook"
}
},
{
@ -445,33 +706,6 @@
"version": "2.0.5"
}
},
{
"name": "poise",
"dependencies": [
],
"version": "2.6.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/poise/versions/2.6.0/download",
"version": "2.6.0"
}
},
{
"name": "poise-service",
"dependencies": [
[
"poise",
"~> 2.0"
]
],
"version": "1.1.1",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/poise-service/versions/1.1.1/download",
"version": "1.1.1"
}
},
{
"name": "application",
"dependencies": [
@ -586,11 +820,11 @@
">= 0.0.0"
]
],
"version": "2.4.0",
"version": "2.5.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/firewall/versions/2.4.0/download",
"version": "2.4.0"
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/firewall/versions/2.5.0/download",
"version": "2.5.0"
}
},
{
@ -620,153 +854,6 @@
"version": "1.0.9"
}
},
{
"name": "nginx",
"dependencies": [
[
"apt",
"~> 2.2"
],
[
"bluepill",
"~> 2.3"
],
[
"build-essential",
"~> 2.0"
],
[
"ohai",
"~> 2.0"
],
[
"runit",
"~> 1.2"
],
[
"yum-epel",
"~> 0.3"
]
],
"version": "2.7.6",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/nginx/versions/2.7.6/download",
"version": "2.7.6"
}
},
{
"name": "bluepill",
"dependencies": [
[
"rsyslog",
"~> 2.0"
]
],
"version": "2.4.1",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/bluepill/versions/2.4.1/download",
"version": "2.4.1"
}
},
{
"name": "rsyslog",
"dependencies": [
],
"version": "2.2.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/rsyslog/versions/2.2.0/download",
"version": "2.2.0"
}
},
{
"name": "ohai",
"dependencies": [
],
"version": "2.1.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/ohai/versions/2.1.0/download",
"version": "2.1.0"
}
},
{
"name": "runit",
"dependencies": [
[
"packagecloud",
">= 0.0.0"
]
],
"version": "1.7.6",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/runit/versions/1.7.6/download",
"version": "1.7.6"
}
},
{
"name": "packagecloud",
"dependencies": [
],
"version": "0.2.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/packagecloud/versions/0.2.0/download",
"version": "0.2.0"
}
},
{
"name": "mysql2_chef_gem",
"dependencies": [
[
"build-essential",
">= 0.0.0"
],
[
"mysql",
"~> 6.0"
],
[
"mariadb",
">= 0.0.0"
]
],
"version": "1.0.2",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/mysql2_chef_gem/versions/1.0.2/download",
"version": "1.0.2"
}
},
{
"name": "mariadb",
"dependencies": [
[
"apt",
">= 0.0.0"
],
[
"yum",
">= 0.0.0"
],
[
"yum-epel",
">= 0.0.0"
]
],
"version": "0.3.1",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/mariadb/versions/0.3.1/download",
"version": "0.3.1"
}
},
{
"name": "omnibus_updater",
"dependencies": [
@ -790,108 +877,6 @@
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/timezone-ii/versions/0.2.0/download",
"version": "0.2.0"
}
},
{
"name": "wordpress",
"dependencies": [
[
"php",
">= 0.0.0"
],
[
"openssl",
">= 0.0.0"
],
[
"apache2",
">= 2.0.0"
],
[
"database",
">= 1.6.0"
],
[
"mysql",
">= 6.0"
],
[
"mysql2_chef_gem",
"~> 1.0.1"
],
[
"build-essential",
">= 0.0.0"
],
[
"iis",
">= 1.6.2"
],
[
"tar",
">= 0.3.1"
],
[
"nginx",
"~> 2.7.4"
],
[
"php-fpm",
"~> 0.6.10"
],
[
"selinux",
"~> 0.7"
]
],
"version": "3.0.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/wordpress/versions/3.0.0/download",
"version": "3.0.0"
}
},
{
"name": "tar",
"dependencies": [
],
"version": "0.7.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/tar/versions/0.7.0/download",
"version": "0.7.0"
}
},
{
"name": "php-fpm",
"dependencies": [
[
"apt",
">= 0.0.0"
],
[
"yum",
">= 3.0.0"
]
],
"version": "0.6.10",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/php-fpm/versions/0.6.10/download",
"version": "0.6.10"
}
},
{
"name": "selinux",
"dependencies": [
],
"version": "0.9.0",
"source": {
"type": "Batali::Source::Site",
"url": "https://supermarket.chef.io:443/api/v1/cookbooks/selinux/versions/0.9.0/download",
"version": "0.9.0"
}
}
]
}

View File

@ -2,6 +2,14 @@ firewall Cookbook CHANGELOG
=======================
This file is used to list changes made in each version of the firewall cookbook.
v2.5.0 (2016-03-08)
-------------------
* Don't modify parameter for port (#120)
* Remove a reference to the wrong variable name under windows (#123)
* Add support for mobile shell default firewall rule (#121)
* New rubocop rules and style fixes
* Correct a README.md example for `action :allow`
v2.4.0 (2016-01-28)
-------------------
* Expose default iptables ruleset so that raw rules can be used in conjunction

View File

@ -87,6 +87,7 @@ The default recipe creates a firewall resource with action install, and if `node
# Attributes
* `default['firewall']['allow_ssh'] = false`, set true to open port 22 for SSH when the default recipe runs
* `default['firewall']['allow_mosh'] = false`, set to true to open UDP ports 60000 - 61000 for [Mosh][0] when the default recipe runs
* `default['firewall']['allow_winrm'] = false`, set true to open port 5989 for WinRM when the default recipe runs
* `default['firewall']['ubuntu_iptables'] = false`, set to true to use iptables on Ubuntu / Debian when using the default recipe
@ -245,7 +246,7 @@ end
firewall_rule 'http/https' do
protocol :tcp
port [80, 443]
action :allow
command :allow
end
firewall 'default' do
@ -321,3 +322,5 @@ 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.
```
[0]: https://mosh.mit.edu/

View File

@ -1,2 +1,3 @@
default['firewall']['allow_ssh'] = false
default['firewall']['allow_winrm'] = false
default['firewall']['allow_mosh'] = false

View File

@ -10,8 +10,8 @@ module FirewallCookbook
elsif p && p.is_a?(Integer)
p.to_s
elsif p && p.is_a?(Array)
p.map! { |o| port_to_s(o) }
p.sort.join(',')
p_strings = p.map { |o| port_to_s(o) }
p_strings.sort.join(',')
elsif p && p.is_a?(Range)
if platform_family?('windows')
"#{p.first}-#{p.last}"
@ -79,10 +79,10 @@ module FirewallCookbook
rules.each do |k, v|
next unless v == sorted_value
contents << if k.start_with?('COMMIT')
'COMMIT'
else
k
end
'COMMIT'
else
k
end
end
end
"#{contents.join("\n")}\n"

View File

@ -42,7 +42,7 @@ module FirewallCookbook
msg << "firewall_rule[#{new_resource.name}] was asked to "
msg << "#{new_resource.command} a stateful rule using #{new_resource.stateful} "
msg << 'but ufw does not support this kind of rule. Consider guarding by platform_family.'
fail msg
raise msg
end
# if we don't do this, ufw will fail as it does not support protocol numbers, so we'll only allow it to run if specifying icmp/tcp/udp protocol types
@ -51,7 +51,7 @@ module FirewallCookbook
msg << "firewall_rule[#{new_resource.name}] was asked to "
msg << "#{new_resource.command} a rule using protocol #{new_resource.protocol} "
msg << 'but ufw does not support this kind of rule. Consider guarding by platform_family.'
fail msg
raise msg
end
# some examples:

View File

@ -66,7 +66,7 @@ module FirewallCookbook
if new_resource.direction.to_sym == :out
parameters['localip'] = new_resource.source ? fixup_cidr(new_resource.source) : 'any'
parameters['localport'] = new_resource.source_port ? port_to_s(new_resource.source_port) : 'any'
parameters['interfacetype'] = new_resource.source_interface ? new_resource.source_interface : 'any'
parameters['interfacetype'] = new_resource.interface ? new_resource.interface : 'any'
parameters['remoteip'] = new_resource.destination ? fixup_cidr(new_resource.destination) : 'any'
parameters['remoteport'] = port_to_s(new_resource.dest_port) ? new_resource.dest_port : 'any'
else

View File

@ -25,7 +25,7 @@ class Chef
return unless new_resource.notify_firewall
firewall_resource = run_context.resource_collection.find(firewall: new_resource.firewall_name)
fail 'could not find a firewall resource' unless firewall_resource
raise 'could not find a firewall resource' unless firewall_resource
new_resource.notifies(:restart, firewall_resource, :delayed)
new_resource.updated_by_last_action(true)

File diff suppressed because one or more lines are too long

View File

@ -39,6 +39,13 @@ firewall_rule 'allow world to winrm' do
only_if { windows? && node['firewall']['allow_winrm'] }
end
firewall_rule 'allow world to mosh' do
protocol :udp
port 60000..61000
source '0.0.0.0/0'
only_if { linux? && node['firewall']['allow_mosh'] }
end
# allow established connections, ufw defaults to this but iptables does not
firewall_rule 'established' do
stateful [:related, :established]

View File

@ -1,16 +1,26 @@
default["mediawiki"]["version"] = "1.23.1"
default["mediawiki"]["webdir"] = node['apache']['docroot_dir'] + "/mediawiki-" + default["mediawiki"]["version"]
default["mediawiki"]["version"] = "1.26.2"
default["mediawiki"]["docroot_dir"] = "/var/www"
default["mediawiki"]["webdir"] = "#{default["mediawiki"]["docroot_dir"]}/mediawiki-#{default["mediawiki"]["version"]}"
default["mediawiki"]["tarball"]["name"] = "mediawiki-" + default["mediawiki"]["version"] + ".tar.gz"
default["mediawiki"]["tarball"]["url"] = "https://releases.wikimedia.org/mediawiki/1.23/" + default["mediawiki"]["tarball"]["name"]
default["mediawiki"]["database"]["name"] = "mediawiki"
default["mediawiki"]["database"]["user"] = "mediawiki"
default["mediawiki"]["database"]["password"] = "Ub3rPa55w0rd"
default["mediawiki"]["tarball"]["url"] = "https://releases.wikimedia.org/mediawiki/1.26/" + default["mediawiki"]["tarball"]["name"]
default["mediawiki"]["server_name"] = "wiki.localhost"
default["mediawiki"]["scriptpath"] = ""
default['mysql']['server_root_password'] = 'Fak3Pa55w0rd'
default["mediawiki"]["server"] = "http://" + default["mediawiki"]["server_name"]
default["mediawiki"]["server"] = "http://" + default["mediawiki"]["server_name"]
default["mediawiki"]["site_name"] = "my Wiki"
default["mediawiki"]["language_code"] = "fr"
default["mediawiki"]["language_code"] = "en"
default["mediawiki"]["admin_user"] = "administrator"
default["mediawiki"]["admin_password"] = "admin"
default["mediawiki"]["php_options"] = { "php_admin_value[upload_max_filesize]" => "50M", "php_admin_value[post_max_size]" => "55M" }
default['mediawiki']['db']['root_password'] = 'my_root_password'
default['mediawiki']['db']['instance_name'] = 'default'
default['mediawiki']['db']['name'] = "mediawikidb"
default['mediawiki']['db']['user'] = "mediawikiuser"
default['mediawiki']['db']['pass'] = nil
default['mediawiki']['db']['prefix'] = 'wp_'
default['mediawiki']['db']['host'] = 'localhost'
default['mediawiki']['db']['port'] = '3307' # Must be a string
default['mediawiki']['db']['charset'] = 'utf8'
default['mediawiki']['db']['collate'] = ''

View File

@ -3,12 +3,15 @@ maintainer 'pulsation'
license 'BSD'
description 'Installs/Configures mediawiki'
long_description 'Installs/Configures mediawiki'
version '0.1.0'
version '0.2.0'
depends 'apache2'
depends 'php'
depends 'mysql'
depends 'database'
depends 'nginx'
depends 'mysql2_chef_gem'
depends 'php-fpm'
attribute 'mediawiki/version',
:display_name => "Mediawiki version",

View File

@ -0,0 +1,10 @@
include_recipe "apache2"
include_recipe "apache2::mod_php5"
include_recipe "apache2::mod_rewrite"
# Add virtualhost
web_app "mediawiki" do
server_name node["mediawiki"]["server_name"]
docroot node["mediawiki"]["webdir"]
end

View File

@ -0,0 +1,63 @@
::Chef::Recipe.send(:include, Opscode::OpenSSL::Password)
node.set_unless['mediawiki']['db']['pass'] = secure_password
node.save unless Chef::Config[:solo]
db = node["mediawiki"]["db"]
mysql_client "default" do
action :create
end
mysql2_chef_gem "default" do
action :install
end
mysql_service db["instance_name"] do
port db["port"]
initial_root_password db["root_password"]
action [:create, :start]
end
socket = "/var/run/mysql-#{db['instance_name']}/mysqld.sock"
if node['platform_family'] == 'debian'
link '/var/run/mysqld/mysqld.sock' do
to socket
not_if 'test -f /var/run/mysqld/mysqld.sock'
end
elsif node['platform_family'] == 'rhel'
link '/var/lib/mysql/mysql.sock' do
to socket
not_if 'test -f /var/lib/mysql/mysql.sock'
end
end
# Database connection information
mysql_connection_info = {
:host => "localhost",
:username => "root",
:socket => socket,
:password => db["root_password"]
}
# Create new database
mysql_database db["name"] do
connection mysql_connection_info
action :create
end
# Create new user
mysql_database_user db["user"] do
connection mysql_connection_info
password db["pass"]
action :create
end
# Grant privilages to user
mysql_database_user db["user"] do
connection mysql_connection_info
database_name db["name"]
privileges [:all]
action :grant
end

View File

@ -8,61 +8,25 @@
#
include_recipe "apt"
include_recipe "apache2"
include_recipe "apache2::mod_php5"
include_recipe "apache2::mod_rewrite"
include_recipe "mysql::server"
include_recipe "database::mysql"
include_recipe "php::default"
include_recipe "php::module_apc"
include_recipe "php::module_mysql"
include_recipe "mediawiki::database"
# Download mediawiki tarball
remote_file "#{Chef::Config[:file_cache_path]}/" + node['mediawiki']['tarball']['name'] do
remote_file "#{Chef::Config[:file_cache_path]}/#{node['mediawiki']['tarball']['name']}" do
source node['mediawiki']['tarball']['url']
notifies :run, "bash[extract_mediawiki]", :immediately
end
# Extract mediawiki tarball
bash "extract_mediawkiki" do
bash "extract_mediawiki" do
user "root"
cwd node['apache']['docroot_dir']
code "tar -zxf #{Chef::Config[:file_cache_path]}/" + node['mediawiki']['tarball']['name']
action :run
end
# Database connection information
mysql_connection_info = {
:host => 'localhost',
:username => 'root',
:password => node['mysql']['server_root_password']
}
# Create new database
mysql_database node['mediawiki']['database']['name'] do
connection mysql_connection_info
action :create
end
# Create new user
mysql_database_user node['mediawiki']['database']['user'] do
connection mysql_connection_info
password node['mediawiki']['database']['password']
action :create
end
# Grant privilages to user
mysql_database_user node['mediawiki']['database']['user'] do
connection mysql_connection_info
database_name node["mediawiki"]["database"]["name"]
privileges [:all]
action :grant
end
# Add virtualhost
web_app "mediawiki" do
server_name node["mediawiki"]["server_name"]
docroot node["mediawiki"]["webdir"]
cwd node["mediawiki"]["docroot_dir"]
code "tar -zxf #{Chef::Config[:file_cache_path]}/#{node['mediawiki']['tarball']['name']}; chown -R #{node['nginx']['user']}:#{node['nginx']['group']} #{node['mediawiki']['docroot_dir']}"
action :nothing
end
# Additional packages
@ -70,31 +34,33 @@ case node["platform_family"]
when "rhel"
package "php-xml"
package "libicu-devel"
service "apache2" do
action :restart
end
when "debian"
package "libicu-dev"
end
php_pear "intl" do
action :install
action :install
end
# Configure mediawiki database
bash "configure_mediawkiki_database" do
user "root"
cwd node["mediawiki"]["webdir"]
code "php maintenance/install.php" +
" --pass '" + node["mediawiki"]["admin_password"] +
"' --dbname '" + node["mediawiki"]["database"]["name"] +
"' --dbpass '" + node["mediawiki"]["database"]["password"] +
"' --dbuser '" + node["mediawiki"]["database"]["name"] +
"' --server '" + node["mediawiki"]["server"] +
"' --scriptpath '" + node["mediawiki"]["scriptpath"] +
bash "configure_mediawiki_database" do
user node["nginx"]["user"]
cwd node["mediawiki"]["webdir"]
code "php maintenance/install.php" +
" --pass '" + node["mediawiki"]["admin_password"] +
"' --dbname '" + node["mediawiki"]["db"]["name"] +
"' --dbpass '" + node["mediawiki"]["db"]["pass"] +
"' --dbuser '" + node["mediawiki"]["db"]["user"] +
"' --server '" + node["mediawiki"]["server"] +
"' --scriptpath '" + node["mediawiki"]["scriptpath"] +
"' --lang '" + node["mediawiki"]["language_code"] +
"' '" + node["mediawiki"]["site_name"] + "' '" + node["mediawiki"]["admin_user"] + "'"
action :run
not_if { File.exist? "#{node["mediawiki"]["webdir"]}/LocalSettings.php" }
action :run
end
file "#{node["mediawiki"]["webdir"]}/LocalSettings.php" do
mode "0640"
owner node["nginx"]["user"]
group node["nginx"]["group"]
end

View File

@ -0,0 +1,59 @@
#
# Cookbook Name:: mediawiki
# Recipe:: nginx
#
node.set_unless['php-fpm']['pools'] = []
include_recipe "php-fpm"
include_recipe 'php-fpm::repository' unless node['php-fpm']['skip_repository_install']
if node['php-fpm']['package_name'].nil?
if platform_family?("rhel")
php_fpm_package_name = "php-fpm"
else
php_fpm_package_name = "php5-fpm"
end
else
php_fpm_package_name = node['php-fpm']['package_name']
end
package php_fpm_package_name do
action :install
end
if node['php-fpm']['service_name'].nil?
php_fpm_service_name = php_fpm_package_name
else
php_fpm_service_name = node['php-fpm']['service_name']
end
service "php-fpm" do
service_name php_fpm_service_name
supports :start => true, :stop => true, :restart => true, :reload => true
action [ :enable, :start ]
end
php_fpm_pool "www" do
enable false
end
php_fpm_pool "mediawiki" do
listen "127.0.0.1:9002"
user node['nginx']['user']
group node['nginx']['group']
listen_owner node['nginx']['user']
listen_group node['nginx']['group']
php_options node['mediawiki']['php_options']
start_servers 5
enable true
end
include_recipe "php::module_mysql"
include_recipe "nginx"
directory node["mediawiki"]["docroot_dir"] do
user node['nginx']['user']
group node['nginx']['group']
recursive true
end

View File

@ -0,0 +1 @@
~FC005

View File

@ -1,156 +1,163 @@
mysql Cookbook CHANGELOG
========================
# mysql Cookbook CHANGELOG
v6.1.2 (2015-10-05)
--------------------
- Amazon Linux 2015.09
This file is used to list changes made in each version of the mysql cookbook.
## v6.1.3 (2016-03-14)
- Added support for Ubuntu 15.10
- Added support for Amazon Linux 2016-03
- Updated Kitchen testing configs
## v6.1.2 (2015-10-05)
- Added support for Amazon Linux 2015.09
## v6.1.1 (2015-09-24)
v6.1.1 (2015-09-24)
--------------------
- Completing ChefSpec matchers
v6.1.0 (2015-07-17)
--------------------
## v6.1.0 (2015-07-17)
- Adding tunables for tmp_dir, error_log, and pid_file
- Adding mysqld_options hash interface for main my.cnf template
v6.0.31 (2015-07-13)
--------------------
## v6.0.31 (2015-07-13)
- Reverting create_stop_system_service checks
v6.0.30 (2015-07-13)
--------------------
## v6.0.30 (2015-07-13)
- Ubuntu 15.04 support
- Check for scripts and unit files during create_stop_system_service
v6.0.29 (2015-07-12)
--------------------
## v6.0.29 (2015-07-12)
- Patch to allow blank root password
- Adding package information for Suse 12.0
v6.0.28 (2015-07-10)
--------------------
## v6.0.28 (2015-07-10)
- Fixes for 12.4.x
v6.0.27 (2015-07-09)
--------------------
## v6.0.27 (2015-07-09)
- Allowing integer value for port number
v6.0.26 (2015-07-07)
--------------------
## v6.0.26 (2015-07-07)
- Reverting breaking changes introduced in 6.0.25
v6.0.25 (2015-07-06)
--------------------
## v6.0.25 (2015-07-06)
- Fixes for 12.4.1
v6.0.24 (2015-06-27)
--------------------
- #341 - Changing default GRANT for root from '%' to 'localhost' and '127.0.0.1'
## v6.0.24 (2015-06-27)
v6.0.23 (2015-06-21)
--------------------
- #354 Better handling of long MySQL startup times
- 341 - Changing default GRANT for root from '%' to 'localhost' and '127.0.0.1'
## v6.0.23 (2015-06-21)
- 354 Better handling of long MySQL startup times
## v6.0.22 (2015-05-07)
v6.0.22 (2015-05-07)
--------------------
- Debian 8 (Jessie) support
v6.0.21 (2015-04-08)
--------------------
## v6.0.21 (2015-04-08)
- Fix to Upstart prestart script when using custom socket
- Adding --explicit_defaults_for_timestamp mysql_install_db_cmd for
5.6 and above
- 5.6 and above
v6.0.20 (2015-03-27)
--------------------
- #318 - Fixing Upstart pre-start script to handle custom socket paths
## v6.0.20 (2015-03-27)
- 318 - Fixing Upstart pre-start script to handle custom socket paths
## v6.0.19 (2015-03-25)
v6.0.19 (2015-03-25)
--------------------
- Adding support for Amazon Linux 2015.03
v6.0.18 (2015-03-24)
--------------------
## v6.0.18 (2015-03-24)
- Adding support for 5.6 and 5.7 packages from dotdeb repos on Debian 7
v6.0.17 (2015-03-13)
--------------------
## v6.0.17 (2015-03-13)
- Updated for MySQL 5.7.6.
- Handing removal of mysql_install_db and mysqld_safe
v6.0.16 (2015-03-10)
--------------------
## v6.0.16 (2015-03-10)
- Moved --defaults-file as first option to mysql_install_db_script
v6.0.15 (2015-02-26)
--------------------
## v6.0.15 (2015-02-26)
- Updating docker detection fix to pass specs
v6.0.14 (2015-02-26)
--------------------
## v6.0.14 (2015-02-26)
- Fixed debian system service :disable action. Now survives reboot
- Fixing centos-7 instance :enable action. Now survives
- Not applying Apparmor policy if running in a Docker container
v6.0.13 (2015-02-15)
--------------------
## v6.0.13 (2015-02-15)
- Adding support for special characters in initial_root_password
- Fixing failure status bug in sysvinit script
v6.0.12 (2015-02-30)
--------------------
- No changes. Released a 6.0.11 that was identical to 6.0.10.
Git before coffee.
## v6.0.12 (2015-02-30)
- No changes. Released a 6.0.11 that was identical to 6.0.10.
- Git before coffee.
## v6.0.11 (2015-02-30)
v6.0.11 (2015-02-30)
--------------------
- Adding support for configurable socket files
v6.0.10 (2015-01-19)
------------------
## v6.0.10 (2015-01-19)
- Fix #282 - Fixing up data_dir template variable
v6.0.9 (2015-01-19)
------------------
## v6.0.9 (2015-01-19)
- Fix #282 - undefined method `parsed_data_dir' bug
v6.0.8 (2015-01-19)
------------------
## v6.0.8 (2015-01-19)
- Refactoring helper methods out of resource classes
v6.0.7 (2015-01-14)
------------------
- Fixing timing issue with Upstart provider :restart and :reload
actions where service returns before being available
## v6.0.7 (2015-01-14)
- Fixing timing issue with Upstart provider :restart and :reload
- actions where service returns before being available
## v6.0.6 (2014-12-26)
v6.0.6 (2014-12-26)
------------------
- Fixing subtle bug where MysqlCookbook::Helper methods were polluting Chef::Resource
v6.0.5 (2014-12-25)
------------------
## v6.0.5 (2014-12-25)
- Using 'include_recipe' instead of 'recipe_eval' in LWRP
- Fixing type checking on package_name attribute in mysql_client resource.
v6.0.4 (2014-12-21)
------------------
## v6.0.4 (2014-12-21)
- Suggest available versions if current is not available for current platform.
v6.0.3 (2014-12-17)
------------------
## v6.0.3 (2014-12-17)
- Adding bind_address parameter to mysql_service resource
v6.0.2 (2014-12-17)
------------------
## v6.0.2 (2014-12-17)
- Fixing sysvinit provider to survive reboots
v6.0.1 (2014-12-16)
------------------
## v6.0.1 (2014-12-16)
- Fixing Upstart template to survive reboots
v6.0.0 (2014-12-15)
------------------
## v6.0.0 (2014-12-15)
- Major version update
- Cookbook now provides LWRPs instead of recipes
- Platform providers re-factored into init system providers
@ -164,12 +171,12 @@ v6.0.0 (2014-12-15)
- Refactored acceptance tests
- Temporarily dropped FreeBSD support
v5.6.1 (2014-10-29)
------------------
## v5.6.1 (2014-10-29)
- Use Gem::Version instead of Chef::Version
v5.6.0 (2014-10-29)
------------------
## v5.6.0 (2014-10-29)
- Changing default charset to utf8
- Quoting passwords in debian.cnf.erb
- Amazon 2014.09 support
@ -177,47 +184,47 @@ v5.6.0 (2014-10-29)
- Only hide passwords from STDOUT via "sensitive true" in chef-client higher than 11.14
- Updating test harness
v5.5.4 (2014-10-07)
------------------
## v5.5.4 (2014-10-07)
- Adding sensitive flag to execute resources to protect passwords from logs
v5.5.3 (2014-09-24)
------------------
## v5.5.3 (2014-09-24)
- Reverting back to Upstart on Ubuntu 14.04
v5.5.2 (2014-09-8)
------------------
## v5.5.2 (2014-09-8)
- Reverting commit that broke Debian pass_string
v5.5.1 (2014-09-2)
------------------
## v5.5.1 (2014-09-2)
- Switching Ubuntu service provider to use SysVinit instead of Upstart
v5.5.0 (2014-08-27)
-------------------
## v5.5.0 (2014-08-27)
- Adding package version and action parameters to mysql_service resource
- Fixing Debian pass_string
v5.4.4 (2014-08-27)
-------------------
## v5.4.4 (2014-08-27)
- Changing module namespace to MysqlCookbook
v5.4.3 (2014-08-25)
-------------------
## v5.4.3 (2014-08-25)
- More refactoring. Moving helper function bits into resource parsed_parameters
v5.4.2 (2014-08-25)
-------------------
## v5.4.2 (2014-08-25)
- Moving provider local variables into definitions for RHEL provider
v5.4.1 (2014-08-25)
-------------------
## v5.4.1 (2014-08-25)
- Refactoring resources into the LWRP style with parsed parameters
- Moving provider local variables into definitions
v5.4.0 (2014-08-25)
-------------------
- #212 - support for centos-7 (mysql55 and mysql56)
## v5.4.0 (2014-08-25)
- 212 - support for centos-7 (mysql55 and mysql56)
- Adding (untested) Debian-6 support
- Adding Suse support to metadata.rb
- Adding ability to change MySQL root password
@ -225,198 +232,170 @@ v5.4.0 (2014-08-25)
- Appeasing AppArmor
- Reducing duplication in client provider
v5.3.6 (2014-06-18)
-------------------
## v5.3.6 (2014-06-18)
- Fixing pid path location. Updating tests to include real RHEL
## v5.3.4 (2014-06-16)
v5.3.4 (2014-06-16)
-------------------
- Fixing specs for Amazon Linux server package names
## v5.3.2 (2014-06-16)
v5.3.2 (2014-06-16)
-------------------
- Fixing Amazon Linux support
## v5.3.0 (2014-06-11)
v5.3.0 (2014-06-11)
-------------------
- #189 - Fix server_repl_password description
- #191 - Adding support for server55 and server56 on el-6
- #193 - Fix syntax in mysql_service example
- #199 - Adding Suse support
- 189 - Fix server_repl_password description
- 191 - Adding support for server55 and server56 on el-6
- 193 - Fix syntax in mysql_service example
- 199 - Adding Suse support
## v5.2.12 (2014-05-19)
v5.2.12 (2014-05-19)
--------------------
PR #192 - recipes/server.rb should honor parameter node['mysql']['version']
## v5.2.10 (2014-05-15)
v5.2.10 (2014-05-15)
--------------------
- COOK-4394 - restore freebsd support
## v5.2.8 (2014-05-15)
v5.2.8 (2014-05-15)
-------------------
- [COOK-4653] - Missing mySQL 5.6 support for Ubuntu 14.04
## v5.2.6 (2014-05-07)
v5.2.6 (2014-05-07)
-------------------
- [COOK-4625] - Fix password resource parameter consumption on Debian and Ubuntu
- Fix up typos and version numbers in PLATFORMS.md
- Fix up specs from COOK-4613 changes
## v5.2.4 (2014-05-02)
v5.2.4 (2014-05-02)
-------------------
- [COOK-4613] - Fix permissions on mysql data_dir to allow global access to mysql.sock
## v5.2.2 (2014-04-24)
v5.2.2 (2014-04-24)
-------------------
- [COOK-4564] - Using positive tests for datadir move
## v5.2.0 (2014-04-22)
v5.2.0 (2014-04-22)
-------------------
- [COOK-4551] - power grants.sql from resource parameters
## v5.1.12 (2014-04-21)
v5.1.12 (2014-04-21)
--------------------
- [COOK-4554] - Support for Debian Sid
## v5.1.10 (2014-04-21)
v5.1.10 (2014-04-21)
--------------------
- [COOK-4565] Support for Ubuntu 14.04
- [COOK-4565] Adding Specs and TK platform
- Removing non-LTS 13.10 specs and TK platform
## v5.1.8 (2014-04-12)
v5.1.8 (2014-04-12)
-------------------
Adding Ubuntu 13.04 to Platforminfo
## v5.1.6 (2014-04-11)
v5.1.6 (2014-04-11)
-------------------
- [COOK-4548] - Add template[/etc/mysql/debian.cnf] to Ubuntu provider
## v5.1.4 (2014-04-11)
v5.1.4 (2014-04-11)
-------------------
- [COOK-4547] - Shellescape server_root_password
## v5.1.2 (2014-04-09)
v5.1.2 (2014-04-09)
-------------------
- [COOK-4519] - Fix error in run_dir for Ubuntu
- [COOK-4531] - Fix pid and run_dir for Debian
## v5.1.0 (2014-04-08)
v5.1.0 (2014-04-08)
-------------------
[COOK-4523] - Allow for both :restart and :reload
## v5.0.6 (2014-04-07)
v5.0.6 (2014-04-07)
-------------------
- [COOK-4519] - Updating specs to reflect pid file change on Ubuntu
## v5.0.4 (2014-04-07)
v5.0.4 (2014-04-07)
-------------------
- [COOK-4519] - Fix path to pid file on Ubuntu
## v5.0.2 (2014-04-01)
v5.0.2 (2014-04-01)
-------------------
- Moving server_deprecated into recipes directory
## v5.0.0 (2014-03-31)
v5.0.0 (2014-03-31)
-------------------
- Rewriting as a library cookbook
- Exposing mysql_service and mysql_client resources
- User now needs to supply configuration
- Moving attribute driven recipe to server-deprecated
## v4.1.2 (2014-02-28)
v4.1.2 (2014-02-28)
-------------------
- [COOK-4349] - Fix invalid platform check
- [COOK-4184] - Better handling of Ubuntu upstart service
- [COOK-2100] - Changing innodb_log_file_size tunable results in inability to start MySQL
## v4.1.1 (2014-02-25)
v4.1.1 (2014-02-25)
-------------------
- **[COOK-2966] - Address foodcritic failures'
- **[COOK-4182] - Template parse failure in /etc/init/mysql.conf (data_dir)'
- **[COOK-4198] - Added missing tunable'
- **[COOK-4206] - create root@127.0.0.1, as well as root@localhost'
## v4.0.20 (2014-01-18)
v4.0.20 (2014-01-18)
--------------------
* [COOK-3931] - MySQL Server Recipe Regression for Non-LTS Ubuntu Versions
* [COOK-3945] - MySQL cookbook fails on Ubuntu 13.04/13.10
* [COOK-3966] - mysql::server recipe can't find a template with debian 7.x
* [COOK-3985] - Missing /etc/mysql/debian.cnf template on mysql::_server_debian.rb recipe (mysql 4.0.4)
* [COOK-3974] - debian.cnf not updated
* [COOK-4001] - Pull request: Fixes for broken mysql::server on Debian
* [COOK-4071] - Mysql cookbook doesn't work on debian 7.2
- [COOK-3931] - MySQL Server Recipe Regression for Non-LTS Ubuntu Versions
- [COOK-3945] - MySQL cookbook fails on Ubuntu 13.04/13.10
- [COOK-3966] - mysql::server recipe can't find a template with debian 7.x
- [COOK-3985] - Missing /etc/mysql/debian.cnf template on mysql::_server_debian.rb recipe (mysql 4.0.4)
- [COOK-3974] - debian.cnf not updated
- [COOK-4001] - Pull request: Fixes for broken mysql::server on Debian
- [COOK-4071] - Mysql cookbook doesn't work on debian 7.2
## v4.0.14
v4.0.14
-------
Fixing style cops
## v4.0.12
v4.0.12
-------
### Bug
- **[COOK-4068](https://tickets.chef.io/browse/COOK-4068)** - rework MySQL Windows recipe
### Improvement
- **[COOK-3801](https://tickets.chef.io/browse/COOK-3801)** - Add innodb_adaptive_flushing_method and innodb_adaptive_checkpoint
## v4.0.10
v4.0.10
-------
fixing metadata version error. locking to 3.0
## v4.0.8
v4.0.8
------
Locking yum dependency to '< 3'
## v4.0.6
v4.0.6
------
# Bug
- [COOK-3943] Notifying service restart on grants update
## v4.0.4
v4.0.4
------
[COOK-3952] - Adding 'recursive true' to directory resources
## v4.0.2
v4.0.2
------
### BUGS
- Adding support for Amazon Linux in attributes/server_rhel.rb
- Fixing bug where unprivileged users cannot connect over a local socket. Adding integration test.
- Fixing bug in mysql_grants_cmd generation
## v4.0.0
v4.0.0
------
- [COOK-3928] Heavily refactoring for readability. Moving platform implementation into separate recipes
- Moving integration tests from minitest to serverspec, removing "improper" tests
- Moving many attributes into the ['mysql']['server']['whatever'] namespace
@ -426,27 +405,26 @@ v4.0.0
- [COOK-3807] - Don't use execute[assign-root-password] on Debian and Ubuntu
- [COOK-3881] - Fixing /etc being owned by mysql user
## v3.0.12
v3.0.12
-------
### Bug
- **[COOK-3752](https://tickets.chef.io/browse/COOK-3752)** - mysql service fails to start in mysql::server recipe
## v3.0.10
v3.0.10
-------
- Fix a failed release attempt for v3.0.8
## v3.0.8
v3.0.8
------
### Bug
- **[COOK-3749](https://tickets.chef.io/browse/COOK-3749)** - Fix a regression with Chef 11-specific features
## v3.0.6
v3.0.6
------
### Bug
- **[COOK-3674](https://tickets.chef.io/browse/COOK-3674)** - Fix an issue where the MySQL server fails to set the root password correctly when `data_dir` is a non-default value
- **[COOK-3647](https://tickets.chef.io/browse/COOK-3647)** - Fix README typo (databas => database)
- **[COOK-3477](https://tickets.chef.io/browse/COOK-3477)** - Fix log-queries-not-using-indexes not working
@ -457,30 +435,33 @@ v3.0.6
- **[COOK-2606](https://tickets.chef.io/browse/COOK-2606)** - Use proper bind address on cloud providers
### Improvement
- **[COOK-3498](https://tickets.chef.io/browse/COOK-3498)** - Add support for replicate_* variables in my.cnf
## v3.0.4
v3.0.4
------
### Bug
- **[COOK-3310](https://tickets.chef.io/browse/COOK-3310)** - Fix missing `GRANT` option
- **[COOK-3233](https://tickets.chef.io/browse/COOK-3233)** - Fix escaping special characters
- **[COOK-3156](https://tickets.chef.io/browse/COOK-3156)** - Fix GRANTS file when `remote_root_acl` is specified
- **[COOK-3134](https://tickets.chef.io/browse/COOK-3134)** - Fix Chef 11 support
- **[COOK-2318](https://tickets.chef.io/browse/COOK-2318)** - Remove redundant `if` block around `node.mysql.tunable.log_bin`
v3.0.2
------
## v3.0.2
### Bug
- [COOK-2158]: apt-get update is run twice at compile time
- [COOK-2832]: mysql grants.sql file has errors depending on attrs
- [COOK-2995]: server.rb is missing a platform_family comparison value
### Sub-task
- [COOK-2102]: `innodb_flush_log_at_trx_commit` value is incorrectly set based on CPU count
v3.0.0
------
## v3.0.0
**Note** This is a backwards incompatible version with previous versions of the cookbook. Tickets that introduce incompatibility are COOK-2615 and COOK-2617.
- [COOK-2478] - Duplicate 'read_only' server attribute in base and tunable
@ -501,24 +482,24 @@ v3.0.0
- [COOK-2618] - myisam-recover not using attribute value
- [COOK-2617] - open-files is a duplicate of open-files-limit
v2.1.2
------
## v2.1.2
- [COOK-2172] - Mysql cookbook duplicates `binlog_format` configuration
v2.1.0
------
## v2.1.0
- [COOK-1669] - Using platform("ubuntu") in default attributes always returns true
- [COOK-1694] - Added additional my.cnf fields and reorganized cookbook to avoid race conditions with mysql startup and sql script execution
- [COOK-1851] - Support server-id and binlog_format settings
- [COOK-1929] - Update msyql server attributes file because setting attributes without specifying a precedence is deprecated
- [COOK-1999] - Add read_only tunable useful for replication slave servers
v2.0.2
------
## v2.0.2
- [COOK-1967] - mysql: trailing comma in server.rb platform family
v2.0.0
------
## v2.0.0
**Important note for this release**
Under Chef Solo, you must set the node attributes for the root, debian and repl passwords or the run will completely fail. See COOK-1737 for background on this.
@ -534,8 +515,8 @@ Under Chef Solo, you must set the node attributes for the root, debian and repl
- [COOK-1769] - link to database recipe in mysql README goes to old chef/cookbooks repo instead of chef-cookbook organization
- [COOK-1963] - use `platform_family`
v1.3.0
------
## v1.3.0
**Important note for this release**
This version no longer installs Ruby bindings in the client recipe by default. Use the ruby recipe if you'd like the RubyGem. If you'd like packages from your distribution, use them in your application's specific cookbook/recipe, or modify the client packages attribute. This resolves the following tickets:
@ -558,56 +539,56 @@ The following issues are also addressed in this release.
- [COOK-934] - remove deprecated mysql/libraries/database.rb, use the database cookbook instead.
- [COOK-1475] - fix restart on config change
v1.2.6
------
## v1.2.6
- [COOK-1113] - Use an attribute to determine if upstart is used
- [COOK-1121] - Add support for Windows
- [COOK-1140] - Fix conf.d on Debian
- [COOK-1151] - Fix server_ec2 handling /var/lib/mysql bind mount
- [COOK-1321] - Document setting password attributes for solo
v1.2.4
------
## v1.2.4
- [COOK-992] - fix FATAL nameerror
- [COOK-827] - `mysql:server_ec2` recipe can't mount `data_dir`
- [COOK-945] - FreeBSD support
v1.2.2
------
## v1.2.2
- [COOK-826] mysql::server recipe doesn't quote password string
- [COOK-834] Add 'scientific' and 'amazon' platforms to mysql cookbook
v1.2.1
------
## v1.2.1
- [COOK-644] Mysql client cookbook 'package missing' error message is confusing
- [COOK-645] RHEL6/CentOS6 - mysql cookbook contains 'skip-federated' directive which is unsupported on MySQL 5.1
v1.2.0
------
## v1.2.0
- [COOK-684] remove mysql_database LWRP
v1.0.8
------
## v1.0.8
- [COOK-633] ensure "cloud" attribute is available
v1.0.7
------
## v1.0.7
- [COOK-614] expose all mysql tunable settings in config
- [COOK-617] bind to private IP if available
v1.0.6
------
## v1.0.6
- [COOK-605] install mysql-client package on ubuntu/debian
v1.0.5
------
## v1.0.5
- [COOK-465] allow optional remote root connections to mysql
- [COOK-455] improve platform version handling
- externalize conf_dir attribute for easier cross platform support
- change datadir attribute to data_dir for consistency
v1.0.4
------
## v1.0.4
- fix regressions on debian platform
- [COOK-578] wrap root password in quotes
- [COOK-562] expose all tunables in my.cnf

View File

@ -0,0 +1,2 @@
Please refer to
https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD

View File

@ -0,0 +1,19 @@
<!-- This is a generated file. Please do not edit directly -->
# Maintainers
This file lists how this cookbook project is maintained. When making changes to the system, this
file tells you who needs to review your patch - you need a simple majority of maintainers
for the relevant subsystems to provide a :+1: on your pull request. Additionally, you need
to not receive a veto from a Lieutenant or the Project Lead.
Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD)
for details on the process and how to become a maintainer or the project lead.
# Project Maintainer
* [Tim Smith](https://github.com/tas50)
# Maintainers
* [Jennifer Davis](https://github.com/sigje)
* [Sean OMeara](https://github.com/someara)
* [Tim Smith](https://github.com/tas50)
* [Thom May](https://github.com/thommay)

View File

@ -1,28 +1,22 @@
MySQL Cookbook
=====================
# MySQL Cookbook
[![Join the chat at https://gitter.im/chef-cookbooks/mysql](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/chef-cookbooks/mysql?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/chef-cookbooks/mysql.svg?branch=master)](https://travis-ci.org/chef-cookbooks/mysql) [![Cookbook Version](https://img.shields.io/cookbook/v/mysql.svg)](https://supermarket.chef.io/cookbooks/mysql)
The Mysql Cookbook is a library cookbook that provides resource primitives
(LWRPs) for use in recipes. It is designed to be a reference example for
creating highly reusable cross-platform cookbooks.
The Mysql Cookbook is a library cookbook that provides resource primitives (LWRPs) for use in recipes. It is designed to be a reference example for creating highly reusable cross-platform cookbooks.
Scope
-----
This cookbook is concerned with the "MySQL Community Server",
particularly those shipped with F/OSS Unix and Linux distributions. It
does not address forks or value-added repackaged MySQL distributions
like Drizzle, MariaDB, or Percona.
## Scope
This cookbook is concerned with the "MySQL Community Server", particularly those shipped with F/OSS Unix and Linux distributions. It does not address forks or value-added repackaged MySQL distributions like Drizzle, MariaDB, or Percona.
## Requirements
Requirements
------------
- Chef 11 or higher
- Ruby 1.9 or higher (preferably from the Chef full-stack installer)
- Network accessible package repositories
- 'recipe[selinux::disabled]' on RHEL platforms
Platform Support
----------------
## Platform Support
The following platforms have been tested with Test Kitchen:
```
@ -31,8 +25,6 @@ The following platforms have been tested with Test Kitchen:
|----------------+-----+-----+-----+-----+-----|
| debian-7 | | | X | | |
|----------------+-----+-----+-----+-----+-----|
| ubuntu-10.04 | | X | | | |
|----------------+-----+-----+-----+-----+-----|
| ubuntu-12.04 | | | X | | |
|----------------+-----+-----+-----+-----+-----|
| ubuntu-14.04 | | | X | X | |
@ -47,24 +39,21 @@ The following platforms have been tested with Test Kitchen:
|----------------+-----+-----+-----+-----+-----|
| amazon | | | X | X | X |
|----------------+-----+-----+-----+-----+-----|
| fedora-20 | | | X | X | X |
| fedora-22 | | | X | X | X |
|----------------+-----+-----+-----+-----+-----|
| suse-11.3 | | | X | | |
|----------------+-----+-----+-----+-----+-----|
| omnios-151006 | | | X | X | |
|----------------+-----+-----+-----+-----+-----|
| smartos-14.3.0 | | | X | X | |
| fedora-23 | | | X | X | X |
|----------------+-----+-----+-----+-----+-----|
```
Cookbook Dependencies
------------
## Cookbook Dependencies
- yum-mysql-community
- smf
Usage
-----
## Usage
Place a dependency on the mysql cookbook in your cookbook's metadata.rb
```ruby
depends 'mysql', '~> 6.0'
```
@ -80,11 +69,9 @@ mysql_service 'foo' do
end
```
The service name on the OS is `mysql-foo`. You can manually start and
stop it with `service mysql-foo start` and `service mysql-foo stop`.
The service name on the OS is `mysql-foo`. You can manually start and stop it with `service mysql-foo start` and `service mysql-foo stop`.
The configuration file is at `/etc/mysql-foo/my.cnf`. It contains the
minimum options to get the service running. It looks like this.
The configuration file is at `/etc/mysql-foo/my.cnf`. It contains the minimum options to get the service running. It looks like this.
```
# Chef generated my.cnf for instance mysql-foo
@ -111,8 +98,7 @@ log-error = /var/log/mysql-foo/error.log
socket = /var/run/mysql-foo/mysqld.sock
```
You can put extra configuration into the conf.d directory by using the
`mysql_config` resource, like this:
You can put extra configuration into the conf.d directory by using the `mysql_config` resource, like this:
```ruby
mysql_service 'foo' do
@ -129,130 +115,65 @@ mysql_config 'foo' do
end
```
You are responsible for providing `my_extra_settings.erb` in your own
cookbook's templates folder.
You are responsible for providing `my_extra_settings.erb` in your own cookbook's templates folder.
Connecting with the mysql CLI command
-------------------------------------
Logging into the machine and typing `mysql` with no extra arguments
will fail. You need to explicitly connect over the socket with `mysql
-S /var/run/mysql-foo/mysqld.sock`, or over the network with `mysql -h
127.0.0.1`
## Connecting with the mysql CLI command
Upgrading from older version of the mysql cookbook
--------------------------------------------------
- It is strongly recommended that you rebuild the machine from
scratch. This is easy if you have your `data_dir` on a dedicated
mount point. If you *must* upgrade in-place, follow the instructions
below.
Logging into the machine and typing `mysql` with no extra arguments will fail. You need to explicitly connect over the socket with `mysql -S /var/run/mysql-foo/mysqld.sock`, or over the network with `mysql -h 127.0.0.1`
- The 6.x series supports multiple service instances on a single
machine. It dynamically names the support directories and service
names. `/etc/mysql becomes /etc/mysql-instance_name`. Other support
directories in `/var` `/run` etc work the same way. Make sure to
specify the `data_dir` property on the `mysql_service` resource to
point to the old `/var/lib/mysql` directory.
## Upgrading from older version of the mysql cookbook
- It is strongly recommended that you rebuild the machine from scratch. This is easy if you have your `data_dir` on a dedicated mount point. If you _must_ upgrade in-place, follow the instructions below.
- The 6.x series supports multiple service instances on a single machine. It dynamically names the support directories and service names. `/etc/mysql becomes /etc/mysql-instance_name`. Other support directories in `/var` `/run` etc work the same way. Make sure to specify the `data_dir` property on the `mysql_service` resource to point to the old `/var/lib/mysql` directory.
## Resources Overview
Resources Overview
------------------
### mysql_service
The `mysql_service` resource manages the basic plumbing needed to get a
MySQL server instance running with minimal configuration.
The `mysql_service` resource manages the basic plumbing needed to get a MySQL server instance running with minimal configuration.
The `:create` action handles package installation, support
directories, socket files, and other operating system level concerns.
The internal configuration file contains just enough to get the
service up and running, then loads extra configuration from a conf.d
directory. Further configurations are managed with the `mysql_config` resource.
The `:create` action handles package installation, support directories, socket files, and other operating system level concerns. The internal configuration file contains just enough to get the service up and running, then loads extra configuration from a conf.d directory. Further configurations are managed with the `mysql_config` resource.
- If the `data_dir` is empty, a database will be initialized, and a
root user will be set up with `initial_root_password`. If this
directory already contains database files, no action will be taken.
- root user will be set up with `initial_root_password`. If this
- directory already contains database files, no action will be taken.
The `:start` action starts the service on the machine using the
appropriate provider for the platform. The `:start` action should be
omitted when used in recipes designed to build containers.
The `:start` action starts the service on the machine using the appropriate provider for the platform. The `:start` action should be omitted when used in recipes designed to build containers.
#### Example
```ruby
mysql_service 'default' do
version '5.7'
bind_address '0.0.0.0'
port '3306'
port '3306'
data_dir '/data'
initial_root_password 'Ch4ng3me'
action [:create, :start]
end
```
Please note that when using `notifies` or `subscribes`, the resource
to reference is `mysql_service[name]`, not `service[mysql]`.
Please note that when using `notifies` or `subscribes`, the resource to reference is `mysql_service[name]`, not `service[mysql]`.
#### Parameters
- `charset` - specifies the default character set. Defaults to `utf8`.
- `data_dir` - determines where the actual data files are kept
on the machine. This is useful when mounting external storage. When
omitted, it will default to the platform's native location.
- `data_dir` - determines where the actual data files are kept on the machine. This is useful when mounting external storage. When omitted, it will default to the platform's native location.
- `error_log` - Tunable location of the error_log
- `initial_root_password` - allows the user to specify the initial
root password for mysql when initializing new databases.
This can be set explicitly in a recipe, driven from a node
attribute, or from data_bags. When omitted, it defaults to
`ilikerandompasswords`. Please be sure to change it.
- `instance` - A string to identify the MySQL service. By convention,
to allow for multiple instances of the `mysql_service`, directories
and files on disk are named `mysql-<instance_name>`. Defaults to the
resource name.
- `initial_root_password` - allows the user to specify the initial root password for mysql when initializing new databases. This can be set explicitly in a recipe, driven from a node attribute, or from data_bags. When omitted, it defaults to `ilikerandompasswords`. Please be sure to change it.
- `instance` - A string to identify the MySQL service. By convention, to allow for multiple instances of the `mysql_service`, directories and files on disk are named `mysql-<instance_name>`. Defaults to the resource name.
- `package_action` - Defaults to `:install`.
- `package_name` - Defaults to a value looked up in an internal map.
- `package_version` - Specific version of the package to install,
passed onto the underlying package manager. Defaults to `nil`.
- `bind_address` - determines the listen IP address for the mysqld service. When
omitted, it will be determined by MySQL. If the address is "regular" IPv4/IPv6
address (e.g 127.0.0.1 or ::1), the server accepts TCP/IP connections only for
that particular address. If the address is "0.0.0.0" (IPv4) or "::" (IPv6), the
server accepts TCP/IP connections on all IPv4 or IPv6 interfaces.
- `mysqld_options` - A key value hash of options to be rendered into
the main my.cnf. WARNING - It is highly recommended that you use the
`mysql_config` resource instead of sending extra config into a
`mysql_service` resource. This will allow you to set up
notifications and subscriptions between the service and its
configuration. That being said, this can be useful for adding extra
options needed for database initialization at first run.
- `port` - determines the listen port for the mysqld service. When
omitted, it will default to '3306'.
- `run_group` - The name of the system group the `mysql_service`
should run as. Defaults to 'mysql'.
- `run_user` - The name of the system user the `mysql_service` should
run as. Defaults to 'mysql'.
- `package_version` - Specific version of the package to install,passed onto the underlying package manager. Defaults to `nil`.
- `bind_address` - determines the listen IP address for the mysqld service. When omitted, it will be determined by MySQL. If the address is "regular" IPv4/IPv6address (e.g 127.0.0.1 or ::1), the server accepts TCP/IP connections only for that particular address. If the address is "0.0.0.0" (IPv4) or "::" (IPv6), the server accepts TCP/IP connections on all IPv4 or IPv6 interfaces.
- `mysqld_options` - A key value hash of options to be rendered into the main my.cnf. WARNING - It is highly recommended that you use the `mysql_config` resource instead of sending extra config into a `mysql_service` resource. This will allow you to set up notifications and subscriptions between the service and its configuration. That being said, this can be useful for adding extra options needed for database initialization at first run.
- `port` - determines the listen port for the mysqld service. When omitted, it will default to '3306'.
- `run_group` - The name of the system group the `mysql_service` should run as. Defaults to 'mysql'.
- `run_user` - The name of the system user the `mysql_service` should run as. Defaults to 'mysql'.
- `pid_file` - Tunable location of the pid file.
- `socket` - determines where to write the socket file for the
`mysql_service` instance. Useful when configuring clients on the
same machine to talk over socket and skip the networking stack.
Defaults to a calculated value based on platform and instance name.
- `socket` - determines where to write the socket file for the `mysql_service` instance. Useful when configuring clients on the same machine to talk over socket and skip the networking stack. Defaults to a calculated value based on platform and instance name.
- `tmp_dir` - Tunable location of the tmp_dir
- `version` - allows the user to select from the versions available
for the platform, where applicable. When omitted, it will install
the default MySQL version for the target platform. Available version
numbers are `5.0`, `5.1`, `5.5`, `5.6`, and `5.7`, depending on platform.
- `version` - allows the user to select from the versions available for the platform, where applicable. When omitted, it will install the default MySQL version for the target platform. Available version numbers are `5.0`, `5.1`, `5.5`, `5.6`, and `5.7`, depending on platform.
#### Actions
@ -264,8 +185,8 @@ omitted, it will default to the platform's native location.
- `:reload` - Reloads the underlying operating system service
#### Providers
Chef selects the appropriate provider based on platform and version,
but you can specify one if your platform support it.
Chef selects the appropriate provider based on platform and version, but you can specify one if your platform support it.
```ruby
mysql_service[instance-1] do
@ -276,31 +197,15 @@ mysql_service[instance-1] do
end
```
- `Chef::Provider::MysqlServiceBase` - Configures everything needed t run
a MySQL service except the platform service facility. This provider
should never be used directly. The `:start`, `:stop`, `:restart`, and
`:reload` actions are stubs meant to be overridden by the providers
below.
- `Chef::Provider::MysqlServiceSmf` - Starts a `mysql_service` using
the Service Management Facility, used by Solaris and IllumOS. Manages
the FMRI and method script.
- `Chef::Provider::MysqlServiceSystemd` - Starts a `mysql_service`
using SystemD. Manages the unit file and activation state
- `Chef::Provider::MysqlServiceSysvinit` - Starts a `mysql_service`
using SysVinit. Manages the init script and status.
- `Chef::Provider::MysqlServiceUpstart` - Starts a `mysql_service`
using Upstart. Manages job definitions and status.
- `Chef::Provider::MysqlServiceBase` - Configures everything needed to run a MySQL service except the platform service facility. This provider should never be used directly. The `:start`, `:stop`, `:restart`, and `:reload` actions are stubs meant to be overridden by the providers below.
- `Chef::Provider::MysqlServiceSmf` - Starts a `mysql_service` using the Service Management Facility, used by Solaris and Illumos. Manages the FMRI and method script.
- `Chef::Provider::MysqlServiceSystemd` - Starts a `mysql_service` using SystemD. Manages the unit file and activation state
- `Chef::Provider::MysqlServiceSysvinit` - Starts a `mysql_service` using SysVinit. Manages the init script and status.
- `Chef::Provider::MysqlServiceUpstart` - Starts a `mysql_service` using Upstart. Manages job definitions and status.
### mysql_config
The `mysql_config` resource is a wrapper around the core Chef
`template` resource. Instead of a `path` parameter, it uses the
`instance` parameter to calculate the path on the filesystem where
file is rendered.
The `mysql_config` resource is a wrapper around the core Chef `template` resource. Instead of a `path` parameter, it uses the `instance` parameter to calculate the path on the filesystem where file is rendered.
#### Example
@ -313,38 +218,22 @@ end
#### Parameters
- `config_name` - The base name of the configuration file to be
rendered into the conf.d directory on disk. Defaults to the resource
name.
- `cookbook` - The name of the cookbook to look for the template
source. Defaults to nil
- `config_name` - The base name of the configuration file to be rendered into the conf.d directory on disk. Defaults to the resource name.
- `cookbook` - The name of the cookbook to look for the template source. Defaults to nil
- `group` - System group for file ownership. Defaults to 'mysql'.
- `instance` - Name of the `mysql_service` instance the config is
meant for. Defaults to 'default'.
- `instance` - Name of the `mysql_service` instance the config is meant for. Defaults to 'default'.
- `owner` - System user for file ownership. Defaults to 'mysql'.
- `source` - Template in cookbook to be rendered.
- `variables` - Variables to be passed to the underlying `template`
resource.
- `version` - Version of the `mysql_service` instance the config is
meant for. Used to calculate path. Only necessary when using
packages with unique configuration paths, such as RHEL Software
Collections or OmniOS. Defaults to 'nil'
- `variables` - Variables to be passed to the underlying `template` resource.
- `version` - Version of the `mysql_service` instance the config is meant for. Used to calculate path. Only necessary when using packages with unique configuration paths, such as RHEL Software Collections or OmniOS. Defaults to 'nil'
#### Actions
- `:create` - Renders the template to disk at a path calculated using
the instance parameter.
- `:delete` - Deletes the file from the conf.d directory calculated
using the instance parameter.
- `:create` - Renders the template to disk at a path calculated using the instance parameter.
- `:delete` - Deletes the file from the conf.d directory calculated using the instance parameter.
#### More Examples
```ruby
mysql_service 'instance-1' do
action [:create, :start]
@ -372,15 +261,13 @@ end
```
### mysql_client
The `mysql_client` resource manages the MySQL client binaries and
development libraries.
It is an example of a "singleton" resource. Declaring two
`mysql_client` resources on a machine usually won't yield two separate
copies of the client binaries, except for platforms that support
multiple versions (RHEL SCL, OmniOS).
The `mysql_client` resource manages the MySQL client binaries and development libraries.
It is an example of a "singleton" resource. Declaring two `mysql_client` resources on a machine usually won't yield two separate copies of the client binaries, except for platforms that support multiple versions (RHEL SCL, OmniOS).
#### Example
```ruby
mysql_client 'default' do
action :create
@ -388,26 +275,19 @@ end
```
#### Parameters
- `package_name` - An array of packages to be installed. Defaults to a
value looked up in an internal map.
- `package_version` - Specific versions of the package to install,
passed onto the underlying package manager. Defaults to `nil`.
- `package_name` - An array of packages to be installed. Defaults to a value looked up in an internal map.
- `package_version` - Specific versions of the package to install, passed onto the underlying package manager. Defaults to `nil`.
- `version` - Major MySQL version number of client packages. Only valid on for platforms that support multiple versions, such as RHEL via Software Collections and OmniOS.
- `version` - Major MySQL version number of client packages. Only
valid on for platforms that support multiple versions, such as RHEL
via Software Collections and OmniOS.
#### Actions
- `:create` - Installs the client software
- `:delete` - Removes the client software
Advanced Usage Examples
-----------------------
There are a number of configuration scenarios supported by the use of
resource primitives in recipes. For example, you might want to run
multiple MySQL services, as different users, and mount block devices
that contain pre-existing databases.
## Advanced Usage Examples
There are a number of configuration scenarios supported by the use of resource primitives in recipes. For example, you might want to run multiple MySQL services, as different users, and mount block devices that contain pre-existing databases.
### Multiple Instances as Different Users
@ -472,92 +352,77 @@ end
```
### Replication Testing
Use multiple `mysql_service` instances to test a replication setup.
This particular example serves as a smoke test in Test Kitchen because
it exercises different resources and requires service restarts.
https://github.com/chef-cookbooks/mysql/blob/master/test/fixtures/cookbooks/mysql_replication_test/recipes/default.rb
Use multiple `mysql_service` instances to test a replication setup. This particular example serves as a smoke test in Test Kitchen because it exercises different resources and requires service restarts.
Frequently Asked Questions
--------------------------
<https://github.com/chef-cookbooks/mysql/blob/master/test/fixtures/cookbooks/mysql_replication_test/recipes/default.rb>
## Frequently Asked Questions
### How do I run this behind my firewall?
On Linux, the `mysql_service` resource uses the platform's underlying
package manager to install software. For this to work behind
firewalls, you'll need to either:
On Linux, the `mysql_service` resource uses the platform's underlying package manager to install software. For this to work behind firewalls, you'll need to either:
- Configure the system yum/apt utilities to use a proxy server that
can reach the Internet
- can reach the Internet
- Host a package repository on a network that the machine can talk to
On the RHEL platform_family, applying the `yum::default` recipe will
allow you to drive the `yum_globalconfig` resource with attributes to
change the global yum proxy settings.
On the RHEL platform_family, applying the `yum::default` recipe will allow you to drive the `yum_globalconfig` resource with attributes to change the global yum proxy settings.
If hosting repository mirrors, applying one of the following recipes
and adjust the settings with node attributes.
If hosting repository mirrors, applying one of the following recipes and adjust the settings with node attributes.
- `recipe[yum-centos::default]` from the Supermarket
https://supermarket.chef.io/cookbooks/yum-centos
https://github.com/chef-cookbooks/yum-centos
<https://supermarket.chef.io/cookbooks/yum-centos>
<https://github.com/chef-cookbooks/yum-centos>
- `recipe[yum-mysql-community::default]` from the Supermarket
https://supermarket.chef.io/cookbooks/yum-mysql-community
https://github.com/chef-cookbooks/yum-mysql-community
<https://supermarket.chef.io/cookbooks/yum-mysql-community>
<https://github.com/chef-cookbooks/yum-mysql-community>
### The mysql command line doesn't work
If you log into the machine and type `mysql`, you may see an error
like this one:
If you log into the machine and type `mysql`, you may see an error like this one:
`Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'`
This is because MySQL is hardcoded to read the defined default my.cnf
file, typically at /etc/my.cnf, and this LWRP deletes it to prevent
overlap among multiple MySQL configurations.
This is because MySQL is hardcoded to read the defined default my.cnf file, typically at /etc/my.cnf, and this LWRP deletes it to prevent overlap among multiple MySQL configurations.
To connect to the socket from the command line, check the socket in the relevant my.cnf file and use something like this:
`mysql -S /var/run/mysql-foo/mysqld.sock -Pwhatever`
Or to connect over the network, use something like this:
connect over the network..
Or to connect over the network, use something like this: connect over the network..
`mysql -h 127.0.0.1 -Pwhatever`
These network or socket ssettings can also be put in you
$HOME/.my.cnf, if preferred.
These network or socket ssettings can also be put in you $HOME/.my.cnf, if preferred.
### What about MariaDB, Percona, Drizzle, WebScaleSQL, etc.
MySQL forks are purposefully out of scope for this cookbook. This is
mostly to reduce the testing matrix to a manageable size. Cookbooks
for these technologies can easily be created by copying and adapting
this cookbook. However, there will be differences.
MySQL forks are purposefully out of scope for this cookbook. This is mostly to reduce the testing matrix to a manageable size. Cookbooks for these technologies can easily be created by copying and adapting this cookbook. However, there will be differences.
Package repository locations, package version names, software major
version numbers, supported platform matrices, and the availability of
software such as XtraDB and Galera are the main reasons that creating
multiple cookbooks to make sense.
Package repository locations, package version names, software major version numbers, supported platform matrices, and the availability of software such as XtraDB and Galera are the main reasons that creating multiple cookbooks to make sense.
Warnings
--------
## Warnings
## Hacking / Testing / TODO
Hacking / Testing / TODO
-------------------------
Please refer to the HACKING.md
License & Authors
-----------------
- Author:: Joshua Timberman (<joshua@chef.io>)
- Author:: AJ Christensen (<aj@chef.io>)
- Author:: Seth Chisamore (<schisamo@chef.io>)
- Author:: Brian Bianco (<brian.bianco@gmail.com>)
- Author:: Jesse Howarth (<him@jessehowarth.com>)
- Author:: Andrew Crump (<andrew@kotirisoftware.com>)
- Author:: Christoph Hartmann (<chris@lollyrock.com>)
- Author:: Sean OMeara (<sean@chef.io>)
## License & Authors
- Author:: Joshua Timberman ([joshua@chef.io](mailto:joshua@chef.io))
- Author:: AJ Christensen ([aj@chef.io](mailto:aj@chef.io))
- Author:: Seth Chisamore ([schisamo@chef.io](mailto:schisamo@chef.io))
- Author:: Brian Bianco ([brian.bianco@gmail.com](mailto:brian.bianco@gmail.com))
- Author:: Jesse Howarth ([him@jessehowarth.com](mailto:him@jessehowarth.com))
- Author:: Andrew Crump ([andrew@kotirisoftware.com](mailto:andrew@kotirisoftware.com))
- Author:: Christoph Hartmann ([chris@lollyrock.com](mailto:chris@lollyrock.com))
- Author:: Sean OMeara ([sean@chef.io](mailto:sean@chef.io))
```text
Copyright:: 2009-2014 Chef Software, Inc

View File

@ -280,6 +280,8 @@ EOSQL
@pkginfo.set['debian']['14.10']['5.6']['server_package'] = 'mysql-server-5.6'
@pkginfo.set['debian']['15.04']['5.6']['client_package'] = %w(mysql-client-5.6 libmysqlclient-dev)
@pkginfo.set['debian']['15.04']['5.6']['server_package'] = 'mysql-server-5.6'
@pkginfo.set['debian']['15.10']['5.6']['client_package'] = %w(mysql-client-5.6 libmysqlclient-dev)
@pkginfo.set['debian']['15.10']['5.6']['server_package'] = 'mysql-server-5.6'
@pkginfo.set['debian']['6']['5.1']['client_package'] = %w(mysql-client libmysqlclient-dev)
@pkginfo.set['debian']['6']['5.1']['server_package'] = 'mysql-server-5.1'
@pkginfo.set['debian']['7']['5.5']['client_package'] = %w(mysql-client libmysqlclient-dev)
@ -336,6 +338,14 @@ EOSQL
@pkginfo.set['rhel']['2015.09']['5.6']['server_package'] = 'mysql-community-server'
@pkginfo.set['rhel']['2015.09']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel)
@pkginfo.set['rhel']['2015.09']['5.7']['server_package'] = 'mysql-community-server'
@pkginfo.set['rhel']['2016.03']['5.1']['server_package'] = %w(mysql51 mysql51-devel)
@pkginfo.set['rhel']['2016.03']['5.1']['server_package'] = 'mysql51-server'
@pkginfo.set['rhel']['2016.03']['5.5']['client_package'] = %w(mysql-community-client mysql-community-devel)
@pkginfo.set['rhel']['2016.03']['5.5']['server_package'] = 'mysql-community-server'
@pkginfo.set['rhel']['2016.03']['5.6']['client_package'] = %w(mysql-community-client mysql-community-devel)
@pkginfo.set['rhel']['2016.03']['5.6']['server_package'] = 'mysql-community-server'
@pkginfo.set['rhel']['2016.03']['5.7']['client_package'] = %w(mysql-community-client mysql-community-devel)
@pkginfo.set['rhel']['2016.03']['5.7']['server_package'] = 'mysql-community-server'
@pkginfo.set['rhel']['5']['5.0']['client_package'] = %w(mysql mysql-devel)
@pkginfo.set['rhel']['5']['5.0']['server_package'] = 'mysql-server'
@pkginfo.set['rhel']['5']['5.1']['client_package'] = %w(mysql51-mysql)
@ -382,7 +392,7 @@ EOSQL
Chef::Log.error("Unsupported Version: You requested to install a Mysql #{type_label} version that is not supported by your platform")
Chef::Log.error("Platform: #{platform_family} #{platform_version} - Request Mysql #{type_label} version: #{version}")
Chef::Log.error("Availabe versions for your platform are: #{info.map { |k, _v| k }.join(' - ')}")
fail "Unsupported Mysql #{type_label} Version"
raise "Unsupported Mysql #{type_label} Version"
end
info[version][type]
end
@ -454,6 +464,7 @@ EOSQL
return '5.5' if node['platform_family'] == 'suse'
return '5.6' if node['platform_family'] == 'fedora'
return '5.6' if node['platform_family'] == 'debian' && node['platform_version'] == '15.04'
return '5.6' if node['platform_family'] == 'debian' && node['platform_version'] == '15.10'
end
end
end

View File

@ -3,7 +3,7 @@ class Chef
class MysqlServiceSmf < Chef::Provider::MysqlServiceBase
# FIXME: we should have a service_helper to determine if the platform supports SMF similarly
# to how we handle systemd on linux
if defined?(provides)
if defined?(provides) # foodcritic ~FC023
provides :mysql_service, os: %w(solaris2 omnios smartos openindiana opensolaris nexentacore) do
File.exist?('/usr/sbin/svccfg')
end

View File

@ -3,7 +3,7 @@ require_relative 'provider_mysql_service_base'
class Chef
class Provider
class MysqlServiceSystemd < Chef::Provider::MysqlServiceBase
if defined?(provides)
if defined?(provides) # foodcritic ~FC023
provides :mysql_service, os: 'linux' do
Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
end

View File

@ -3,7 +3,7 @@ require_relative 'provider_mysql_service_base'
class Chef
class Provider
class MysqlServiceUpstart < Chef::Provider::MysqlServiceBase
if defined?(provides)
if defined?(provides) # foodcritic ~FC023
provides :mysql_service, os: 'linux' do
Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart) &&
!Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)

View File

@ -1,7 +1,7 @@
begin
require 'chef/platform/provider_priority_map'
rescue LoadError
rescue LoadError # rubocop: disable Lint/HandleExceptions
end
require_relative 'provider_mysql_service_smf'

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,21 @@
---
driver:
name: vagrant
provisioner:
name: chef_solo
platforms:
- name: ubuntu-12.04
- name: centos-6.4
- name: fedora-21
suites:
- name: default
run_list:
- recipe[php-fpm::default]
attributes:
php-fpm:
pools:
- name: web
listen: '127.0.0.1:9081'

View File

@ -0,0 +1 @@
1.9.3-p327

View File

@ -0,0 +1,3 @@
source "https://supermarket.getchef.com"
metadata

20
cookbooks/php-fpm/Gemfile Normal file
View File

@ -0,0 +1,20 @@
source 'https://rubygems.org'
gem 'berkshelf'
# Uncomment these lines if you want to live on the Edge:
#
# group :development do
# gem "berkshelf", github: "berkshelf/berkshelf"
# gem "vagrant", github: "mitchellh/vagrant", tag: "v1.6.3"
# end
#
# group :plugins do
# gem "vagrant-berkshelf", github: "berkshelf/vagrant-berkshelf"
# gem "vagrant-omnibus", github: "schisamo/vagrant-omnibus"
# end
gem 'test-kitchen'
gem 'kitchen-vagrant'
gem 'stove'
gem 'serverspec'

View File

@ -0,0 +1,179 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (3.2.19)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
addressable (2.3.6)
akami (1.2.2)
gyoku (>= 0.4.0)
nokogiri
berkshelf (2.0.18)
activesupport (~> 3.2.0)
addressable (~> 2.3.4)
buff-shell_out (~> 0.1)
chozo (>= 0.6.1)
faraday (~> 0.8.5)
hashie (~> 2.0)
minitar (~> 0.5.4)
rbzip2 (~> 0.2.0)
retryable (~> 1.3.3)
ridley (~> 1.7.0)
solve (~> 0.8.2)
thor (~> 0.18.0)
buff-config (0.4.0)
buff-extensions (~> 0.3)
varia_model (~> 0.1)
buff-extensions (0.5.0)
buff-ignore (1.1.1)
buff-ruby_engine (0.1.0)
buff-shell_out (0.2.0)
buff-ruby_engine (~> 0.1.0)
builder (3.2.2)
celluloid (0.16.0)
timers (~> 4.0.0)
celluloid-io (0.16.1)
celluloid (>= 0.16.0)
nio4r (>= 1.0.0)
chef-api (0.5.0)
logify (~> 0.1)
mime-types
chozo (0.6.1)
activesupport (>= 3.2.0)
hashie (>= 2.0.2)
multi_json (>= 1.3.0)
diff-lcs (1.2.5)
erubis (2.7.0)
faraday (0.8.9)
multipart-post (~> 1.2.0)
ffi (1.9.6)
gssapi (1.0.3)
ffi (>= 1.0.1)
gyoku (1.2.2)
builder (>= 2.1.2)
hashie (2.1.2)
hitimes (1.2.2)
httpclient (2.5.1)
httpi (0.9.7)
rack
i18n (0.6.11)
json (1.8.1)
kitchen-vagrant (0.15.0)
test-kitchen (~> 1.0)
little-plugger (1.1.3)
logging (1.8.2)
little-plugger (>= 1.1.3)
multi_json (>= 1.8.4)
logify (0.2.0)
mime-types (2.4.2)
mini_portile (0.6.0)
minitar (0.5.4)
mixlib-authentication (1.3.0)
mixlib-log
mixlib-log (1.6.0)
mixlib-shellout (1.6.1)
multi_json (1.10.1)
multipart-post (1.2.0)
net-http-persistent (2.9.4)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (2.9.1)
nio4r (1.0.1)
nokogiri (1.6.3.1)
mini_portile (= 0.6.0)
nori (1.1.5)
rack (1.5.2)
rbzip2 (0.2.0)
retryable (1.3.6)
ridley (1.7.1)
addressable
buff-config (~> 0.2)
buff-extensions (~> 0.3)
buff-ignore (~> 1.1)
buff-shell_out (~> 0.1)
celluloid (~> 0.15)
celluloid-io (~> 0.15)
erubis
faraday (>= 0.8.4)
hashie (>= 2.0.2)
json (>= 1.7.7)
mixlib-authentication (>= 1.3.0)
net-http-persistent (>= 2.8)
net-ssh
retryable
solve (>= 0.4.4)
varia_model (~> 0.1)
winrm (~> 1.1.0)
rspec (3.1.0)
rspec-core (~> 3.1.0)
rspec-expectations (~> 3.1.0)
rspec-mocks (~> 3.1.0)
rspec-core (3.1.7)
rspec-support (~> 3.1.0)
rspec-expectations (3.1.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.1.0)
rspec-its (1.0.1)
rspec-core (>= 2.99.0.beta1)
rspec-expectations (>= 2.99.0.beta1)
rspec-mocks (3.1.3)
rspec-support (~> 3.1.0)
rspec-support (3.1.2)
rubyntlm (0.1.1)
safe_yaml (1.0.4)
savon (0.9.5)
akami (~> 1.0)
builder (>= 2.1.2)
gyoku (>= 0.4.0)
httpi (~> 0.9)
nokogiri (>= 1.4.0)
nori (~> 1.0)
wasabi (~> 1.0)
serverspec (2.3.1)
multi_json
rspec (~> 3.0)
rspec-its
specinfra (~> 2.3)
solve (0.8.2)
specinfra (2.3.0)
net-scp
net-ssh
stove (3.2.3)
chef-api (~> 0.5)
logify (~> 0.2)
test-kitchen (1.2.1)
mixlib-shellout (~> 1.2)
net-scp (~> 1.1)
net-ssh (~> 2.7)
safe_yaml (~> 1.0)
thor (~> 0.18)
thor (0.18.1)
timers (4.0.1)
hitimes
uuidtools (2.1.5)
varia_model (0.3.2)
buff-extensions (~> 0.2)
hashie (>= 2.0.2)
wasabi (1.0.0)
nokogiri (>= 1.4.0)
winrm (1.1.3)
gssapi (~> 1.0.0)
httpclient (~> 2.2, >= 2.2.0.2)
logging (~> 1.6, >= 1.6.1)
nokogiri (~> 1.5)
rubyntlm (~> 0.1.1)
savon (= 0.9.5)
uuidtools (~> 2.1.2)
PLATFORMS
ruby
DEPENDENCIES
berkshelf
kitchen-vagrant
serverspec
stove
test-kitchen
BUNDLED WITH
1.10.3

View File

@ -24,7 +24,7 @@ The `apt_repository` and `yum_repository` LWRPs are used from these cookbooks to
Description
==========
Creates a PHP-FPM configuration file at the path specified. Meant to be deployed with a service init scheme/supervisor such as runit. Please see the `application::php-fpm` recipe for a complete working example. In depth information about PHP-FPM's configuration values can be [found in the PHP-FPM documentation](http://php-fpm.org/wiki/Configuration_File).
Creates a PHP-FPM configuration file at the path specified. Meant to be deployed with a service init scheme/supervisor such as runit. Please see the `application::php-fpm` recipe for a complete working example. In depth information about PHP-FPM's configuration values can be [found in the PHP-FPM documentation](http://php.net/manual/en/install.fpm.configuration.php).
Usage
=====
@ -38,18 +38,18 @@ name "php-fpm"
description "php fpm role"
run_list "recipe[php-fpm]"
override_attributes "php-fpm" => {
"pools" => [
{
:name => "default"
"pools" => {
"default" => {
:enable => true
},
{
:name => "www",
"www" => {
:enable => "true",
:cookbook => "another-cookbook",
:process_manager => "dynamic",
:max_requests => 5000,
:php_options => { 'php_admin_flag[log_errors]' => 'on', 'php_admin_value[memory_limit]' => '32M' }
}
]
}
}
```

View File

@ -0,0 +1,13 @@
begin
require 'kitchen/rake_tasks'
Kitchen::RakeTasks.new
rescue LoadError
puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI']
end
begin
require 'stove/rake_task'
Stove::RakeTask.new
rescue LoadErro
pust ">>>>> Stove gem not loaded, omitting tasks" unless ENV['CI']
end

View File

@ -0,0 +1,12 @@
# encoding: utf-8
require 'bundler'
require 'bundler/setup'
require 'berkshelf/thor'
begin
require 'kitchen/thor_tasks'
Kitchen::ThorTasks.new
rescue LoadError
puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI']
end

90
cookbooks/php-fpm/Vagrantfile vendored Normal file
View File

@ -0,0 +1,90 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.require_version ">= 1.5.0"
Vagrant.configure(VAGRANTFILE_API_VERSION) 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 = "php-fpm-berkshelf"
# Set the version of chef to install using the vagrant-omnibus plugin
config.omnibus.chef_version = :latest
# Every Vagrant virtual environment requires a box to build off of.
# If this value is a shorthand to a box in Vagrant Cloud then
# config.vm.box_url doesn't need to be specified.
# config.vm.box = "chef/ubuntu-14.04"
case ENV['VMBOX']
when 'centos65'
config.vm.box = "opscode-centos-6.5"
config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.5_chef-provisionerless.box"
else
config.vm.box = "opscode-ubuntu-12.04"
config.vm.box_url = "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_ubuntu-12.04_chef-provisionerless.box"
end
# The url from where the 'config.vm.box' box will be fetched if it
# is not a Vagrant Cloud box and if it doesn't already exist on the
# user's system.
# config.vm.box_url = "https://vagrantcloud.com/chef/ubuntu-14.04/version/1/provider/virtualbox.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, type: "dhcp"
config.vm.network :private_network, ip: "33.33.33.10"
# 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.vm.provision :chef_solo do |chef|
chef.run_list = [
"recipe[apt]",
"recipe[php-fpm::default]"
]
end
end

View File

@ -1,4 +1,5 @@
if node.platform_family == "rhel"
case node["platform_family"]
when "rhel", "fedora"
user = "apache"
group = "apache"
conf_dir = "/etc/php.d"
@ -26,18 +27,30 @@ default['php-fpm']['conf_dir'] = conf_dir
default['php-fpm']['pool_conf_dir'] = pool_conf_dir
default['php-fpm']['conf_file'] = conf_file
default['php-fpm']['pid'] = pid
default['php-fpm']['log_dir'] = '/var/log/php-fpm'
default['php-fpm']['error_log'] = error_log
default['php-fpm']['log_level'] = "notice"
default['php-fpm']['emergency_restart_threshold'] = 0
default['php-fpm']['emergency_restart_interval'] = 0
default['php-fpm']['process_control_timeout'] = 0
default['php-fpm']['pools'] = [
{
:name => "www"
default['php-fpm']['pools'] = {
"www" => {
:enable => true
}
]
}
default['php-fpm']['skip_repository_install'] = false
default['php-fpm']['installation_action'] = :install
default['php-fpm']['version'] = nil
default['php-fpm']['yum_url'] = "http://rpms.famillecollet.com/enterprise/$releasever/remi/$basearch/"
default['php-fpm']['yum_mirrorlist'] = "http://rpms.famillecollet.com/enterprise/$releasever/remi/mirror"
case node["platform_family"]
when "rhel"
default['php-fpm']['yum_url'] = "http://rpms.famillecollet.com/enterprise/$releasever/remi/$basearch/"
default['php-fpm']['yum_mirrorlist'] = "http://rpms.famillecollet.com/enterprise/$releasever/remi/mirror"
when "fedora"
default['php-fpm']['skip_repository_install'] = true
end
default['php-fpm']['dotdeb_repository']['uri'] = "http://packages.dotdeb.org"
default['php-fpm']['dotdeb_repository']['key'] = "http://www.dotdeb.org/dotdeb.gpg"
default['php-fpm']['dotdeb-php53_repository']['uri'] = "http://php53.dotdeb.org"

View File

@ -0,0 +1,101 @@
# 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
# Other #
##########
.sandbox
.bundle

View File

@ -48,7 +48,9 @@ define :php_fpm_pool, :template => "pool.conf.erb", :enable => true do
:max_requests => params[:max_requests],
:catch_workers_output => params[:catch_workers_output],
:security_limit_extensions => params[:security_limit_extensions] || node['php-fpm']['security_limit_extensions'],
:access_log => params[:access_log] || false,
:php_options => params[:php_options] || {},
:request_terminate_timeout => params[:request_terminate_timeout],
:params => params
)
notifies :restart, "service[php-fpm]"

View File

@ -1,37 +0,0 @@
{
"name": "php-fpm",
"version": "0.6.10",
"description": "Installs/Configures php-fpm",
"long_description": "Description\n===========\n\nInstalls and configures PHP-FPM (FastCGI Process Manager), an alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busier sites. It's like the `unicorn` of the PHP world dawg.\n\nRequirements\n============\n\nPlatform\n--------\n\n* Debian, Ubuntu\n* CentOS, Red Hat, Fedora\n* Amazon Linux\n\nCookbooks\n---------\n\n* apt (leverages apt_repository LWRP)\n* yum (leverages yum_repository LWRP)\n\nThe `apt_repository` and `yum_repository` LWRPs are used from these cookbooks to create the proper repository entries so the php-fpm package downloaded and installed.\n\nDescription\n==========\n\nCreates a PHP-FPM configuration file at the path specified. Meant to be deployed with a service init scheme/supervisor such as runit. Please see the `application::php-fpm` recipe for a complete working example. In depth information about PHP-FPM's configuration values can be [found in the PHP-FPM documentation](http://php-fpm.org/wiki/Configuration_File).\n\nUsage\n=====\nSimply include the recipe where you want PHP-FPM installed. Default pool __www__ will be created. To disable pool creation set default['php-fpm']['pools'] to false.\n\nTo customize settings and pools you can override default attributes.\n\n### Usage in roles:\n```ruby\nname \"php-fpm\"\ndescription \"php fpm role\"\nrun_list \"recipe[php-fpm]\"\noverride_attributes \"php-fpm\" => {\n\t\"pools\" => [\n\t\t{\n\t\t\t:name => \"default\"\n\t\t},\n\t\t{\n\t\t\t:name => \"www\",\n\t\t\t:cookbook => \"another-cookbook\",\n\t\t\t:process_manager => \"dynamic\",\n\t\t\t:max_requests => 5000,\n\t\t\t:php_options => { 'php_admin_flag[log_errors]' => 'on', 'php_admin_value[memory_limit]' => '32M' }\n\t\t}\n\t]\n}\n```\n\nCreating pools in recipes\n=========================\n### Create PHP-FPM pool named 'www' with default settings:\n```ruby\nphp_fpm_pool \"www\"\n```\n\n### Create PHP-FPM pool named 'www' with custom settings:\n```ruby\nphp_fpm_pool \"www\" do\n cookbook \"another-cookbook\" # get template from another cookbook\n process_manager \"dynamic\"\n max_requests 5000\n php_options 'php_admin_flag[log_errors]' => 'on', 'php_admin_value[memory_limit]' => '32M'\nend\n```\n\n### Delete PHP-FPM pool named 'www':\n```ruby\nphp_fpm_pool \"www\" do\n enable false\nend\n```\n\nLicense and Author\n==================\n\nAuthor:: Seth Chisamore (<schisamo@opscode.com>)\n\nCopyright:: 2011, Opscode, Inc\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
"maintainer": "Opscode, Inc.",
"maintainer_email": "cookbooks@opscode.com",
"license": "Apache 2.0",
"platforms": {
"debian": ">= 0.0.0",
"ubuntu": ">= 0.0.0",
"centos": ">= 0.0.0",
"redhat": ">= 0.0.0",
"fedora": ">= 0.0.0",
"amazon": ">= 0.0.0"
},
"dependencies": {
"apt": ">= 0.0.0",
"yum": ">= 3.0.0"
},
"recommendations": {
},
"suggestions": {
},
"conflicting": {
},
"providing": {
},
"replacing": {
},
"attributes": {
},
"groupings": {
},
"recipes": {
}
}

View File

@ -4,7 +4,7 @@ maintainer_email "cookbooks@opscode.com"
license "Apache 2.0"
description "Installs/Configures php-fpm"
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version "0.6.10"
version "0.7.5"
depends "apt"
depends "yum", ">= 3.0"

View File

@ -28,7 +28,13 @@ end
if node['php-fpm']['pools']
node['php-fpm']['pools'].each do |pool|
php_fpm_pool pool[:name] do
if pool.is_a?(Array)
pool_name = pool[0]
pool = pool[1]
else
pool_name = pool[:name]
end
php_fpm_pool pool_name do
pool.each do |k, v|
self.params[k.to_sym] = v
end

View File

@ -19,9 +19,10 @@
#
include_recipe 'php-fpm::repository' unless node['php-fpm']['skip_repository_install']
include_recipe 'apt::default' if node['platform_family'] == 'debian'
if node['php-fpm']['package_name'].nil?
if platform_family?("rhel")
if platform_family?("rhel", "fedora")
php_fpm_package_name = "php-fpm"
else
php_fpm_package_name = "php5-fpm"
@ -31,7 +32,8 @@ else
end
package php_fpm_package_name do
action :upgrade
action node['php-fpm']['installation_action']
version node['php-fpm']['version'] if node['php-fpm']['version']
end
if node['php-fpm']['service_name'].nil?
@ -40,13 +42,9 @@ else
php_fpm_service_name = node['php-fpm']['service_name']
end
service_provider = nil
if node['platform'] == 'ubuntu' and node['platform_version'].to_f >= 13.10
service_provider = ::Chef::Provider::Service::Upstart
end
directory node['php-fpm']['log_dir']
service "php-fpm" do
provider service_provider if service_provider
service_name php_fpm_service_name
supports :start => true, :stop => true, :restart => true, :reload => true
action [ :enable, :start ]

View File

@ -40,33 +40,33 @@ when 'debian'
# http://www.dotdeb.org/instructions/
if node.platform_version.to_f >= 7.0
apt_repository "dotdeb" do
uri "http://packages.dotdeb.org"
uri node['php-fpm']['dotdeb_repository']['uri']
distribution "stable"
components ['all']
key "http://www.dotdeb.org/dotdeb.gpg"
key node['php-fpm']['dotdeb_repository']['key']
action :add
end
elsif node.platform_version.to_f >= 6.0
apt_repository "dotdeb" do
uri "http://packages.dotdeb.org"
uri node['php-fpm']['dotdeb_repository']['uri']
distribution "squeeze"
components ['all']
key "http://www.dotdeb.org/dotdeb.gpg"
key node['php-fpm']['dotdeb_repository']['key']
action :add
end
else
apt_repository "dotdeb" do
uri "http://packages.dotdeb.org"
uri node['php-fpm']['dotdeb_repository']['uri']
distribution "oldstable"
components ['all']
key "http://www.dotdeb.org/dotdeb.gpg"
key node['php-fpm']['dotdeb_repository']['key']
action :add
end
apt_repository "dotdeb-php53" do
uri "http://php53.dotdeb.org"
uri node['php-fpm']['dotdeb-php53_repository']['uri']
distribution "oldstable"
components ['all']
key "http://www.dotdeb.org/dotdeb.gpg"
key node['php-fpm']['dotdeb_repository']['key']
action :add
end
end

View File

@ -112,7 +112,7 @@ pm.max_children = <%= @max_children || 50 %>
; Note: Used only when pm is set to 'dynamic'
; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2
<% if @start_servers %>
pm.start_servers = <%= @start_servers %>
pm.start_servers = <%= @start_servers %>
<% end %>
; The desired minimum number of idle server processes.
@ -257,7 +257,9 @@ pm.max_requests = <%= @max_requests || 500 %>
; The access log file
; Default: not set
;access.log = log/$pool.access.log
<% if @access_log %>
access.log = <%= node['php-fpm']['log_dir'] %>/$pool.access.log
<% end %>
; The access log format.
; The following syntax is allowed
@ -330,7 +332,7 @@ pm.max_requests = <%= @max_requests || 500 %>
; does not stop script execution for some reason. A value of '0' means 'off'.
; Available units: s(econds)(default), m(inutes), h(ours), or d(ays)
; Default Value: 0
;request_terminate_timeout = 0
request_terminate_timeout = <%=@request_terminate_timeout || 0 %>
; Set open file descriptor rlimit.
; Default Value: system defined value
@ -364,6 +366,7 @@ pm.max_requests = <%= @max_requests || 500 %>
; Default Value: no
catch_workers_output = <%= @catch_workers_output || "no" %>
<% if node['platform'] != 'ubuntu' && node['platform_version'] != '10.04' %>
; Limits the extensions of the main script FPM will allow to parse. This can
; prevent configuration mistakes on the web server side. You should only limit
; FPM to .php extensions to prevent malicious users to use other extensions to
@ -372,6 +375,7 @@ catch_workers_output = <%= @catch_workers_output || "no" %>
; Default Value: .php
;security.limit_extensions = .php .php3 .php4 .php5
security.limit_extensions = <%=@security_limit_extensions || ".php" %>
<% end %>
; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
; the current environment.

View File

@ -0,0 +1,7 @@
require 'serverspec'
set :backend, :exec
describe port(9081) do
it { should be_listening }
end

View File

@ -1,35 +0,0 @@
# Poise-Service Changelog
## v1.1.1
* Fix an incorrect value in `poise_service_test`. This is not relevant to
end-users of `poise-service`.
## v1.1.0
* Added `inittab` provider to manage services using old-fashioned `/etc/inittab`.
## v1.0.4
* Set GID correctly in all service providers.
* Allow overriding the path to the generated sysvinit script.
## v1.0.3
* [#10](https://github.com/poise/poise-service/pull/10) Fixes for ensuring services are restarted when their command or user changes.
* [#11](https://github.com/poise/poise-service/pull/11) Revamp the `sysvinit` provider for non-Debian platforms to be more stable.
* [#12](https://github.com/poise/poise-service/pull/12) Improve the `dummy` provider to handle dropping privs correctly.
## v1.0.2
* Fix a potential infinite loop when starting a service with the dummy provider.
* [#2](https://github.com/poise/poise-service/pull/2) Remove usage of root
default files so uploading with Berkshelf works (for now).
## v1.0.1
* Don't use a shared, mutable default value for `#environment`.
## v1.0.0
* Initial release!

View File

@ -1,410 +0,0 @@
# Poise-Service Cookbook
[![Build Status](https://img.shields.io/travis/poise/poise-service.svg)](https://travis-ci.org/poise/poise-service)
[![Gem Version](https://img.shields.io/gem/v/poise-service.svg)](https://rubygems.org/gems/poise-service)
[![Cookbook Version](https://img.shields.io/cookbook/v/poise-service.svg)](https://supermarket.chef.io/cookbooks/poise-service)
[![Coverage](https://img.shields.io/codecov/c/github/poise/poise-service.svg)](https://codecov.io/github/poise/poise-service)
[![Gemnasium](https://img.shields.io/gemnasium/poise/poise-service.svg)](https://gemnasium.com/poise/poise-service)
[![License](https://img.shields.io/badge/license-Apache_2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
A [Chef](https://www.chef.io/) cookbook to provide a unified interface for
services.
### What is poise-service?
Poise-service is a tool for developers of "library cookbooks" to define a
service without forcing the end-user of the library to adhere to their choice of
service management framework. The `poise_service` resource represents an
abstract service to be run, which can then be customized by node attributes and
the `poise_service_options` resource. This is a technique called [dependency
injection](https://en.wikipedia.org/wiki/Dependency_injection), and allows a
measure of decoupling between the library and application cookbooks.
### Why would I use poise-service?
Poise-service is most useful for authors of library-style cookbooks, for example
the `apache2`, `mysql`, or `application` cookbooks. When using other service
management options with Chef, the author of the library cookbook has to add
specific code for each service management framework they want to support, often
resulting in a cookbook only supporting the favorite framework of the author or
depending on distribution packages for their init scripts. The `poise_service`
resource allows library cookbook authors a way to write generic code for all
service management frameworks while still allowing users of that cookbook to
choose which service management framework best fits their needs.
### How is this different from the built-in service resource?
Chef includes a `service` resource which allows interacting with certain
service management frameworks such as SysV, Upstart, and systemd.
`poise-service` goes further in that it actually generates the configuration
files needed for the requested service management framework, as well as offering
a dependency injection system for application cookbooks to customize which
framework is used.
### What service management frameworks are supported?
* [SysV (aka /etc/init.d)](#sysvinit)
* [Upstart](#upstart)
* [systemd](#systemd)
* [Inittab](#inittab)
* [Runit](https://github.com/poise/poise-service-runit)
* [Monit](https://github.com/poise/poise-monit#service-provider)
* [Solaris](https://github.com/sh9189/poise-service-solaris)
* [AIX](https://github.com/johnbellone/poise-service-aix)
* *Supervisor (coming soon!)*
## Quick Start
To create a service user and a service to run Apache2:
```ruby
poise_service_user 'www-data'
poise_service 'apache2' do
command '/usr/sbin/apache2 -f /etc/apache2/apache2.conf -DFOREGROUND'
stop_signal 'WINCH'
reload_signal 'USR1'
end
```
or for a hypothetical Rails web application:
```ruby
poise_service_user 'myapp'
poise_service 'myapp-web' do
command 'bundle exec unicorn -p 8080'
user 'myapp'
directory '/srv/myapp'
environment RAILS_ENV: 'production'
end
```
## Resources
### `poise_service`
The `poise_service` resource is the abstract definition of a service.
```ruby
poise_service 'myapp' do
command 'myapp --serve'
environment RAILS_ENV: 'production'
end
```
#### Actions
* `:enable` Create, enable and start the service. *(default)*
* `:disable` Stop, disable, and destroy the service.
* `:start` Start the service.
* `:stop` Stop the service.
* `:restart` Stop and then start the service.
* `:reload` Send the configured reload signal to the service.
#### Attributes
* `service_name` Name of the service. *(name attribute)*
* `command` Command to run for the service. This command must stay in the
foreground and not daemonize itself. *(required)*
* `user` User to run the service as. See
[`poise_service_user`](#poise_service_user) for any easy way to create service
users. *(default: root)*
* `directory` Working directory for the service. *(default: home directory for
user, or / if not found)*
* `environment` Environment variables for the service.
* `stop_signal` Signal to use to stop the service. Some systems will fall back
to SIGKILL if this signal fails to stop the process. *(default: TERM)*
* `reload_signal` Signal to use to reload the service. *(default: HUP)*
* `restart_on_update` If true, the service will be restarted if the service
definition or configuration changes. If `'immediately'`, the notification will
happen in immediate mode. *(default: true)*
#### Service Options
The `poise-service` library offers an additional way to pass configuration
information to the final service called "options". Options are key/value pairs
that are passed down to the service provider and can be used to control how it
creates and manages the service. These can be set in the `poise_service`
resource using the `options` method, in node attributes or via the
`poise_service_options` resource. The options from all sources are merged
together in to a single hash.
When setting options in the resource you can either set them for all providers:
```ruby
poise_service 'myapp' do
command 'myapp --serve'
options status_port: 8000
end
```
or for a single provider:
```ruby
poise_service 'myapp' do
command 'myapp --serve'
options :systemd, after_target: 'network'
end
```
Setting via node attributes is generally how an end-user or application cookbook
will set options to customize services in the library cookbooks they are using.
You can set options for all services or for a single service, by service name
or by resource name:
```ruby
# Global, for all services.
override['poise-service']['options']['after_target'] = 'network'
# Single service.
override['poise-service']['myapp']['template'] = 'myapp.erb'
```
The `poise_service_options` resource is also available to set node attributes
for a specific service in a DSL-friendly way:
```ruby
poise_service_options 'myapp' do
template 'myapp.erb'
restart_on_update false
end
```
Unlike resource attributes, service options can be different for each provider.
Not all providers support the same options so make sure to check the
documentation for each provider to see what options are available.
### `poise_service_options`
The `poise_service_options` resource allows setting per-service options in a
DSL-friendly way. See [the Service Options](#service-options) section for more
information about service options overall.
```ruby
poise_service_options 'myapp' do
template 'myapp.erb'
restart_on_update false
end
```
#### Actions
* `:run` Apply the service options. *(default)*
#### Attributes
* `resource` Name of the service. *(name attribute)*
* `for_provider` Provider to set options for.
All other attribute keys will be used as options data.
### `poise_service_user`
The `poise_service_user` resource is an easy way to create service users. It is
not required to use `poise_service`, it is only a helper.
```ruby
poise_service_user 'myapp' do
home '/srv/myapp'
end
```
#### Actions
* `:create` Create the user and group. *(default)*
* `:remove` Remove the user and group.
#### Attributes
* `user` Name of the user. *(name attribute)*
* `group` Name of the group. Set to `false` to disable group creation. *(name attribute)*
* `uid` UID of the user. If unspecified it will be automatically allocated.
* `gid` GID of the group. If unspecified it will be automatically allocated.
* `home` Home directory of the user.
## Providers
### `sysvinit`
The `sysvinit` provider supports SystemV-style init systems on Debian-family and
RHEL-family platforms. It will create the `/etc/init.d/<service_name>` script
and enable/disable the service using the platform-specific service resource.
```ruby
poise_service 'myapp' do
provider :sysvinit
command 'myapp --serve'
end
```
By default a PID file will be created in `/var/run/service_name.pid`. You can
use the `pid_file` option detailed below to override this and rely on your
process creating a PID file in the given path.
#### Options
* `pid_file` Path to PID file that the service command will create.
* `template` Override the default script template. If you want to use a
template in a different cookbook use `'cookbook:template'`.
* `command` Override the service command.
* `directory` Override the service directory.
* `environment` Override the service environment variables.
* `reload_signal` Override the service reload signal.
* `stop_signal` Override the service stop signal.
* `user` Override the service user.
* `never_restart` Never try to restart the service.
* `never_reload` Never try to reload the service.
* `script_path` Override the path to the generated service script.
### `upstart`
The `upstart` provider supports [Upstart](http://upstart.ubuntu.com/). It will
create the `/etc/init/service_name.conf` configuration.
```ruby
poise_service 'myapp' do
provider :upstart
command 'myapp --serve'
end
```
As a wide variety of versions of Upstart are in use in various Linux
distributions, the provider does its best to identify which features are
available and provide shims as appropriate. Most of these should be invisible
however Upstart older than 1.10 does not support setting a `reload signal` so
only SIGHUP can be used. You can set a `reload_shim` option to enable an
internal implementaion of reloading to be used for signals other than SIGHUP,
however as this is implemented inside Chef code, running `initctl reload` would
still result in SIGHUP being sent. For this reason, the feature is disabled by
default and will throw an error if a reload signal other than SIGHUP is used.
#### Options
* `reload_shim` Enable the reload signal shim. See above for a warning about
this feature.
* `template` Override the default configuration template. If you want to use a
template in a different cookbook use `'cookbook:template'`.
* `command` Override the service command.
* `directory` Override the service directory.
* `environment` Override the service environment variables.
* `reload_signal` Override the service reload signal.
* `stop_signal` Override the service stop signal.
* `user` Override the service user.
* `never_restart` Never try to restart the service.
* `never_reload` Never try to reload the service.
### `systemd`
The `systemd` provider supports [systemd](http://www.freedesktop.org/wiki/Software/systemd/).
It will create the `/etc/systemd/system/service_name.service` configuration.
```ruby
poise_service 'myapp' do
provider :systemd
command 'myapp --serve'
end
```
#### Options
* `template` Override the default configuration template. If you want to use a
template in a different cookbook use `'cookbook:template'`.
* `command` Override the service command.
* `directory` Override the service directory.
* `environment` Override the service environment variables.
* `reload_signal` Override the service reload signal.
* `stop_signal` Override the service stop signal.
* `user` Override the service user.
* `never_restart` Never try to restart the service.
* `never_reload` Never try to reload the service.
* `auto_reload` Run `systemctl daemon-reload` after changes to the unit file. *(default: true)*
### `inittab`
The `inittab` provider supports managing services via `/etc/inittab` using
[SystemV Init](http://www.nongnu.org/sysvinit/). This can provide basic
process supervision even on very old *nix machines.
```ruby
poise_service 'myapp' do
provider :inittab
command 'myapp --serve'
end
```
**NOTE:** Inittab does not allow stopping services, and they are started as soon
as they are enabled.
#### Options
* `never_restart` Never try to restart the service.
* `never_reload` Never try to reload the service.
* `pid_file` Path to PID file that the service command will create.
* `service_id` Unique 1-4 character tag for the service. Defaults to an
auto-generated hash based on the service name. If these collide, bad things
happen. Don't do that.
## ServiceMixin
For the common case of a resource (LWRP or plain Ruby) that roughly maps to
"some config files and a service" poise-service provides a mixin module,
`PoiseService::ServiceMixin`. This mixin adds the standard service actions
(`enable`, `disable`, `start`, `stop`, `restart`, and `reload`) with basic
implementations that call those actions on a `poise_service` resource for you.
You customize the service by defining a `service_options` method on your
provider class:
```ruby
def service_options(service)
# service is the PoiseService::Resource object instance.
service.command "/usr/sbin/#{new_resource.name} -f /etc/#{new_resource.name}/conf/httpd.conf -DFOREGROUND"
service.stop_signal 'WINCH'
service.reload_signal 'USR1'
end
```
You will generally want to override the `enable` action to install things
related to the service like packages, users and configuration files:
```ruby
def action_enable
notifying_block do
package 'apache2'
poise_service_user 'www-data'
template "/etc/#{new_resource.name}/conf/httpd.conf" do
# ...
end
end
# This super call will run the normal service enable,
# creating the service and starting it.
super
end
```
See [the poise_service_test_mixin resource](test/cookbooks/poise-service_test/resources/mixin.rb)
and [provider](test/cookbooks/poise-service_test/providers/mixin.rb) for
examples of using `ServiceMixin` in an LWRP.
## Sponsors
Development sponsored by [Bloomberg](http://www.bloomberg.com/company/technology/).
The Poise test server infrastructure is sponsored by [Rackspace](https://rackspace.com/).
## License
Copyright 2015-2016, Noah Kantrowitz
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.

View File

@ -1,19 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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.
#
default['poise-service']['provider'] = 'auto'
default['poise-service']['options'] = {}

View File

@ -1,25 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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.
#
module PoiseService
autoload :Error, 'poise_service/error'
autoload :Resources, 'poise_service/resources'
autoload :ServiceMixin, 'poise_service/service_mixin'
autoload :ServiceProviders, 'poise_service/service_providers'
autoload :Utils, 'poise_service/utils'
autoload :VERSION, 'poise_service/version'
end

View File

@ -1,18 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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 'poise_service/resources'
require 'poise_service/service_providers'

View File

@ -1,20 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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.
#
module PoiseService
class Error < ::Exception
end
end

View File

@ -1,27 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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 'poise_service/resources/poise_service'
require 'poise_service/resources/poise_service_user'
module PoiseService
# Chef resources and providers for poise-service.
#
# @since 1.0.0
module Resources
end
end

View File

@ -1,162 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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 'etc'
require 'chef/mash'
require 'chef/resource'
require 'poise'
require 'poise_service/error'
module PoiseService
module Resources
# (see PoiseService::Resource)
module PoiseService
# `poise_service` resource. Provides a unified service interface with a
# dependency injection framework.
#
# @since 1.0.0
# @provides poise_service
# @action enable
# @action disable
# @action start
# @action stop
# @action restart
# @action reload
# @example
# poise_service 'myapp' do
# command 'myapp --serve'
# user 'myuser'
# directory '/home/myapp'
# end
class Resource < Chef::Resource
include Poise(inversion: true)
provides(:poise_service)
actions(:enable, :disable, :start, :stop, :restart, :reload)
# @!attribute service_name
# Name of the service to the underlying init system. Defaults to the name
# of the resource.
# @return [String]
attribute(:service_name, kind_of: String, name_attribute: true)
# @!attribute command
# Command to run inside the service. This command must remain in the
# foreground and not daemoinize itself.
# @return [String]
attribute(:command, kind_of: String, required: true)
# @!attribute user
# User to run the service as. See {UserResource} for an easy way to
# create service users. Defaults to root.
# @return [String]
attribute(:user, kind_of: String, default: 'root')
# @!attribute directory
# Working directory for the service. Defaults to the home directory of
# the configured user or / if not found.
# @return [String]
attribute(:directory, kind_of: String, default: lazy { default_directory })
# @!attribute environment
# Environment variables for the service.
# @return [Hash]
attribute(:environment, kind_of: Hash, default: lazy { Mash.new })
# @!attribute stop_signal
# Signal to use to stop the service. Some systems will fall back to
# KILL if this signal fails to stop the process. Defaults to TERM.
# @return [String, Symbol, Integer]
attribute(:stop_signal, kind_of: [String, Symbol, Integer], default: 'TERM')
# @!attribute reload_signal
# Signal to use to reload the service. Defaults to HUP.
# @return [String, Symbol, Integer]
attribute(:reload_signal, kind_of: [String, Symbol, Integer], default: 'HUP')
# @!attribute restart_on_update
# If true, the service will be restarted if the service definition or
# configuration changes. If 'immediately', the notification will happen
# in immediate mode.
# @return [Boolean, String]
attribute(:restart_on_update, equal_to: [true, false, 'immediately', :immediately], default: true)
# Resource DSL callback.
#
# @api private
def after_created
# Set signals to clean values.
stop_signal(clean_signal(stop_signal))
reload_signal(clean_signal(reload_signal))
end
# Return the PID of the main process for this service or nil if the service
# isn't running or the PID cannot be found.
#
# @return [Integer, nil]
# @example
# execute "kill -WINCH #{resources('poise_test[myapp]').pid}"
def pid
# :pid isn't a real action, but this should still work.
provider_for_action(:pid).pid
end
private
# Try to find the home diretory for the configured user. This will fail if
# nsswitch.conf was changed during this run such as with LDAP. Defaults to
# the system root directory.
#
# @see #directory
# @return [String]
def default_directory
# For root we always want the system root path.
unless user == 'root'
# Force a reload in case any users were created earlier in the run.
Etc.endpwent
home = begin
Dir.home(user)
rescue ArgumentError
nil
end
end
# Better than nothing
home || case node['platform_family']
when 'windows'
ENV.fetch('SystemRoot', 'C:\\')
else
'/'
end
end
# Clean up a signal string/integer. Ints are mapped to the signal name,
# and strings are reformatted to upper case and without the SIG.
#
# @see #stop_signal
# @param signal [String, Symbol, Integer] Signal value to clean.
# @return [String]
def clean_signal(signal)
if signal.is_a?(Integer)
raise Error.new("Unknown signal #{signal}") unless (0..31).include?(signal)
Signal.signame(signal)
else
short_sig = signal.to_s.upcase
short_sig = short_sig[3..-1] if short_sig.start_with?('SIG')
raise Error.new("Unknown signal #{signal}") unless Signal.list.include?(short_sig)
short_sig
end
end
# Providers can be found under service_providers/.
end
end
end
end

View File

@ -1,241 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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/resource'
require 'chef/provider'
require 'poise'
module PoiseService
module Resources
# (see PoiseServiceTest::Resource)
module PoiseServiceTest
# A `poise_service_test` resource for integration testing service providers.
# This is used in Test-Kitchen tests to ensure all providers behave
# similarly.
#
# @since 1.0.0
# @provides poise_service_test
# @action run
# @example
# poise_service_test 'upstart' do
# service_provider :upstart
# base_port 5000
# end
class Resource < Chef::Resource
include Poise
provides(:poise_service_test)
actions(:run)
# @!attribute service_provider
# Service provider to set for the test group.
# @return [Symbol]
attribute(:service_provider, kind_of: Symbol)
# @!attribute service_options
# Service options to set for the test group.
# @return [Hash, nil]
attribute(:service_options, kind_of: [Hash, NilClass])
# @!attribute base_port
# Port number to start from for the test group.
# @return [Integer]
attribute(:base_port, kind_of: Integer)
end
# Provider for `poise_service_test`.
#
# @see Resource
# @provides poise_service_test
class Provider < Chef::Provider
include Poise
provides(:poise_service_test)
SERVICE_SCRIPT = <<-EOH
require 'webrick'
require 'json'
require 'etc'
FILE_DATA = ''
server = WEBrick::HTTPServer.new(Port: ARGV[0].to_i)
server.mount_proc '/' do |req, res|
res.body = {
directory: Dir.getwd,
user: Etc.getpwuid(Process.uid).name,
euser: Etc.getpwuid(Process.euid).name,
group: Etc.getgrgid(Process.gid).name,
egroup: Etc.getgrgid(Process.egid).name,
environment: ENV.to_hash,
file_data: FILE_DATA,
pid: Process.pid,
}.to_json
end
EOH
# `run` action for `poise_service_test`. Create all test services.
#
# @return [void]
def action_run
notifying_block do
create_script
create_noterm_script
create_user
create_tests
end
end
private
def create_script
file '/usr/bin/poise_test' do
owner 'root'
group 'root'
mode '755'
content <<-EOH
#!/opt/chef/embedded/bin/ruby
#{SERVICE_SCRIPT}
def load_file
FILE_DATA.replace(IO.read(ARGV[1]))
end
if ARGV[1]
load_file
trap('HUP') do
load_file
end
end
server.start
EOH
end
end
def create_noterm_script
file '/usr/bin/poise_test_noterm' do
owner 'root'
group 'root'
mode '755'
content <<-EOH
#!/opt/chef/embedded/bin/ruby
trap('HUP', 'IGNORE')
trap('STOP', 'IGNORE')
trap('TERM', 'IGNORE')
#{SERVICE_SCRIPT}
while true
begin
server.start
rescue Exception
rescue StandardError
end
end
EOH
end
end
def create_user
poise_service_user 'poise' do
home '/tmp'
end
end
def create_tests
poise_service "poise_test_#{new_resource.name}" do
if new_resource.service_provider
provider new_resource.service_provider
options new_resource.service_provider, new_resource.service_options if new_resource.service_options
end
command "/usr/bin/poise_test #{new_resource.base_port}"
end
poise_service "poise_test_#{new_resource.name}_params" do
if new_resource.service_provider
provider new_resource.service_provider
options new_resource.service_provider, new_resource.service_options if new_resource.service_options
end
command "/usr/bin/poise_test #{new_resource.base_port + 1}"
environment POISE_ENV: new_resource.name
user 'poise'
end
poise_service "poise_test_#{new_resource.name}_noterm" do
if new_resource.service_provider
provider new_resource.service_provider
options new_resource.service_provider, new_resource.service_options if new_resource.service_options
end
action [:enable, :disable]
command "/usr/bin/poise_test_noterm #{new_resource.base_port + 2}"
stop_signal 'kill'
end
{'restart' => 3, 'reload' => 4}.each do |action, port|
# Stop it before writing the file so we always start with first.
poise_service "poise_test_#{new_resource.name}_#{action} stop" do
if new_resource.service_provider
provider new_resource.service_provider
options new_resource.service_provider, new_resource.service_options if new_resource.service_options
end
action(:disable)
service_name "poise_test_#{new_resource.name}_#{action}"
end
# Write the content to the read on service launch.
file "/etc/poise_test_#{new_resource.name}_#{action}" do
content 'first'
end
# Launch the service, reading in first.
poise_service "poise_test_#{new_resource.name}_#{action}" do
if new_resource.service_provider
provider new_resource.service_provider
options new_resource.service_provider, new_resource.service_options if new_resource.service_options
end
command "/usr/bin/poise_test #{new_resource.base_port + port} /etc/poise_test_#{new_resource.name}_#{action}"
end
# Rewrite the file to second, restart/reload to trigger an update.
file "/etc/poise_test_#{new_resource.name}_#{action} again" do
path "/etc/poise_test_#{new_resource.name}_#{action}"
content 'second'
notifies action.to_sym, "poise_service[poise_test_#{new_resource.name}_#{action}]"
end
end
# Test the #pid accessor.
ruby_block "/tmp/poise_test_#{new_resource.name}_pid" do
block do
pid = resources("poise_service[poise_test_#{new_resource.name}]").pid
IO.write("/tmp/poise_test_#{new_resource.name}_pid", pid.to_s)
end
end
# Test changing the service definition itself.
poise_service "poise_test_#{new_resource.name}_change" do
if new_resource.service_provider
provider new_resource.service_provider
options new_resource.service_provider, new_resource.service_options if new_resource.service_options
end
command "/usr/bin/poise_test #{new_resource.base_port + 5}"
end
poise_service "poise_test_#{new_resource.name}_change_second" do
service_name "poise_test_#{new_resource.name}_change"
if new_resource.service_provider
provider new_resource.service_provider
options new_resource.service_provider, new_resource.service_options if new_resource.service_options
end
command "/usr/bin/poise_test #{new_resource.base_port + 6}"
end
end
end
end
end
end

View File

@ -1,138 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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/resource'
require 'chef/provider'
require 'poise'
module PoiseService
module Resources
# (see PoiseServiceUser::Resource)
# @since 1.0.0
module PoiseServiceUser
# A `poise_service_user` resource to create service users/groups.
#
# @since 1.0.0
# @provides poise_service_user
# @action create
# @action remove
# @example
# poise_service_user 'myapp' do
# home '/var/tmp'
# group 'nogroup'
# end
class Resource < Chef::Resource
include Poise
provides(:poise_service_user)
actions(:create, :remove)
# @!attribute user
# Name of the user to create. Defaults to the name of the resource.
# @return [String]
attribute(:user, kind_of: String, name_attribute: true)
# @!attribute group
# Name of the group to create. Defaults to the name of the resource.
# Set to false to disable group creation.
# @return [String, false]
attribute(:group, kind_of: [String, FalseClass], name_attribute: true)
# @!attribute uid
# UID of the user to create. Optional, if not set the UID will be
# allocated automatically.
# @return [Integer]
attribute(:uid, kind_of: Integer)
# @!attribute gid
# GID of the group to create. Optional, if not set the GID will be
# allocated automatically.
# @return [Integer]
attribute(:gid, kind_of: Integer)
# @!attribute home
# Home directory of the user. This directory will not be created if it
# does not exist. Optional.
# @return [String]
attribute(:home, kind_of: String)
end
# Provider for `poise_service_user`.
#
# @since 1.0.0
# @see Resource
# @provides poise_service_user
class Provider < Chef::Provider
include Poise
provides(:poise_service_user)
# `create` action for `poise_service_user`. Ensure the user and group (if
# enabled) exist.
#
# @return [void]
def action_create
notifying_block do
create_group if new_resource.group
create_user
end
end
# `remove` action for `poise_service_user`. Ensure the user and group (if
# enabled) are destroyed.
#
# @return [void]
def action_remove
notifying_block do
remove_user
remove_group if new_resource.group
end
end
private
# Create the system group.
def create_group
group new_resource.group do
gid new_resource.gid
system true
end
end
# Create the system user.
def create_user
user new_resource.user do
comment "Service user for #{new_resource.name}"
gid new_resource.group if new_resource.group
home new_resource.home
shell '/bin/false'
system true
uid new_resource.uid
end
end
# Remove the system group.
def remove_group
create_group.tap do |r|
r.action(:remove)
end
end
# Remove the system user.
def remove_user
create_user.tap do |r|
r.action(:remove)
end
end
end
end
end
end

View File

@ -1,192 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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 'poise'
require 'poise_service/resources/poise_service'
module PoiseService
# Mixin for application services. This is any resource that will be part of
# an application deployment and involves running a persistent service.
#
# @since 1.0.0
# @example
# module MyApp
# class Resource < Chef::Resource
# include Poise
# provides(:my_app)
# include PoiseService::ServiceMixin
# end
#
# class Provider < Chef::Provider
# include Poise
# provides(:my_app)
# include PoiseService::ServiceMixin
#
# def action_enable
# notifying_block do
# template '/etc/myapp.conf' do
# # ...
# end
# end
# super
# end
#
# def service_options(r)
# r.command('myapp --serve')
# end
# end
# end
module ServiceMixin
include Poise::Utils::ResourceProviderMixin
# Mixin for service wrapper resources.
#
# @see ServiceMixin
module Resource
include Poise::Resource
module ClassMethods
# @api private
def included(klass)
super
klass.extend(ClassMethods)
klass.class_exec do
actions(:enable, :disable, :start, :stop, :restart, :reload)
attribute(:service_name, kind_of: String, name_attribute: true)
end
end
end
extend ClassMethods
end
# Mixin for service wrapper providers.
#
# @see ServiceMixin
module Provider
include Poise::Provider
# Default enable action for service wrappers.
#
# @return [void]
def action_enable
notify_if_service do
service_resource.run_action(:enable)
end
end
# Default disable action for service wrappers.
#
# @return [void]
def action_disable
notify_if_service do
service_resource.run_action(:disable)
end
end
# Default start action for service wrappers.
#
# @return [void]
def action_start
notify_if_service do
service_resource.run_action(:start)
end
end
# Default stop action for service wrappers.
#
# @return [void]
def action_stop
notify_if_service do
service_resource.run_action(:stop)
end
end
# Default restart action for service wrappers.
#
# @return [void]
def action_restart
notify_if_service do
service_resource.run_action(:restart)
end
end
# Default reload action for service wrappers.
#
# @return [void]
def action_reload
notify_if_service do
service_resource.run_action(:reload)
end
end
# @todo Add reload once poise-service supports it.
private
# Set the current resource as notified if the provided block updates the
# service resource.
#
# @api public
# @param block [Proc] Block to run.
# @return [void]
# @example
# notify_if_service do
# service_resource.run_action(:enable)
# end
def notify_if_service(&block)
service_resource.updated_by_last_action(false)
block.call if block
new_resource.updated_by_last_action(true) if service_resource.updated_by_last_action?
end
# Service resource for this service wrapper. This returns a
# poise_service resource that will not be added to the resource
# collection. Override {#service_options} to set service resource
# parameters.
#
# @api public
# @return [Chef::Resource]
# @example
# service_resource.run_action(:restart)
def service_resource
@service_resource ||= PoiseService::Resources::PoiseService::Resource.new(new_resource.name, run_context).tap do |r|
# Set some defaults.
r.enclosing_provider = self
r.source_line = new_resource.source_line
r.service_name(new_resource.service_name)
# Call the subclass hook for more specific settings.
service_options(r)
end
end
# Abstract hook to set parameters on {#service_resource} when it is
# created. This is required to set at least `resource.command`.
#
# @api public
# @param resource [Chef::Resource] Resource instance to set parameters on.
# @return [void]
# @example
# def service_options(resource)
# resource.command('myapp --serve')
# end
def service_options(resource)
end
end
end
end

View File

@ -1,38 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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/platform/provider_priority_map'
require 'poise_service/service_providers/dummy'
require 'poise_service/service_providers/inittab'
require 'poise_service/service_providers/systemd'
require 'poise_service/service_providers/sysvinit'
require 'poise_service/service_providers/upstart'
module PoiseService
# Inversion providers for the poise_service resource.
#
# @since 1.0.0
module ServiceProviders
# Set up priority maps
Chef::Platform::ProviderPriorityMap.instance.priority(:poise_service, [
PoiseService::ServiceProviders::Systemd,
PoiseService::ServiceProviders::Upstart,
PoiseService::ServiceProviders::Sysvinit,
])
end
end

View File

@ -1,193 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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/provider'
require 'poise'
module PoiseService
module ServiceProviders
class Base < Chef::Provider
include Poise(inversion: :poise_service)
# Extend the default lookup behavior to check for service_name too.
#
# @api private
def self.resolve_inversion_provider(node, resource)
attrs = resolve_inversion_attribute(node)
(attrs[resource.service_name] && attrs[resource.service_name]['provider']) || super
end
# Extend the default options to check for service_name too.
#
# @api private
def self.inversion_options(node, resource)
super.tap do |opts|
attrs = resolve_inversion_attribute(node)
opts.update(attrs[resource.service_name]) if attrs[resource.service_name]
run_state = Mash.new(node.run_state.fetch('poise_inversion', {}).fetch(inversion_resource, {}))[resource.service_name] || {}
opts.update(run_state['*']) if run_state['*']
opts.update(run_state[provides]) if run_state[provides]
end
end
# Cache the service hints to improve performance. This is called from the
# provides_auto? on most service providers and hits the filesystem a lot.
#
# @return [Array<Symbol>]
def self.service_resource_hints
@@service_resource_hints ||= Chef::Platform::ServiceHelpers.service_resource_providers
end
def action_enable
include_recipe(*Array(recipes)) if recipes
notifying_block do
create_service
end
enable_service
action_start
end
def action_disable
action_stop
disable_service
notifying_block do
destroy_service
end
end
def action_start
notify_if_service do
service_resource.run_action(:start)
end
end
def action_stop
notify_if_service do
service_resource.run_action(:stop)
end
end
def action_restart
return if options['never_restart']
notify_if_service do
service_resource.run_action(:restart)
end
end
def action_reload
return if options['never_reload']
notify_if_service do
service_resource.run_action(:reload)
end
end
def pid
raise NotImplementedError
end
private
# Recipes to include for this provider to work. Subclasses can override.
#
# @return [String, Array]
def recipes
end
# Subclass hook to create the required files et al for the service.
def create_service
raise NotImplementedError
end
# Subclass hook to remove the required files et al for the service.
def destroy_service
raise NotImplementedError
end
def enable_service
notify_if_service do
service_resource.run_action(:enable)
end
end
def disable_service
notify_if_service do
service_resource.run_action(:disable)
end
end
def notify_if_service(&block)
service_resource.updated_by_last_action(false)
block.call
new_resource.updated_by_last_action(true) if service_resource.updated_by_last_action?
end
# Subclass hook to create the resource used to delegate start, stop, and
# restart actions.
def service_resource
@service_resource ||= Chef::Resource::Service.new(new_resource.service_name, run_context).tap do |r|
r.enclosing_provider = self
r.source_line = new_resource.source_line
r.supports(status: true, restart: true, reload: true)
end
end
def service_template(path, default_source, &block)
# Sigh scoping.
template path do
owner 'root'
group 'root'
mode '644'
if options['template']
# If we have a template override, allow specifying a cookbook via
# "cookbook:template".
parts = options['template'].split(/:/, 2)
if parts.length == 2
source parts[1]
cookbook parts[0]
else
source parts.first
cookbook new_resource.cookbook_name.to_s
end
else
source default_source
cookbook 'poise-service'
end
variables(
command: options['command'] || new_resource.command,
directory: options['directory'] || new_resource.directory,
environment: options['environment'] || new_resource.environment,
name: new_resource.service_name,
new_resource: new_resource,
options: options,
reload_signal: options['reload_signal'] || new_resource.reload_signal,
stop_signal: options['stop_signal'] || new_resource.stop_signal,
user: options['user'] || new_resource.user,
)
# Don't trigger a restart if the template doesn't already exist, this
# prevents restarting on the run that first creates the service.
restart_on_update = options.fetch('restart_on_update', new_resource.restart_on_update)
if restart_on_update && ::File.exist?(path)
mode = restart_on_update.to_s == 'immediately' ? :immediately : :delayed
notifies :restart, new_resource, mode
end
instance_exec(&block) if block
end
end
end
end
end

View File

@ -1,156 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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 'etc'
require 'shellwords'
require 'poise_service/service_providers/base'
module PoiseService
module ServiceProviders
class Dummy < Base
provides(:dummy)
def action_start
return if pid
Chef::Log.debug("[#{new_resource}] Starting #{new_resource.command}")
# Clear the pid file if it exists.
::File.unlink(pid_file) if ::File.exist?(pid_file)
if Process.fork
# Parent, wait for the final child to write the pid file.
now = Time.now
until ::File.exist?(pid_file)
sleep(1)
# After 30 seconds, show output at a higher level to avoid too much
# confusing on failed process launches.
if Time.now - now <= 30
Chef::Log.debug("[#{new_resource}] Waiting for PID file")
else
Chef::Log.warning("[#{new_resource}] Waiting for PID file at #{pid_file} to be created")
end
end
else
# :nocov:
Chef::Log.debug("[#{new_resource}] Forked")
# First child, daemonize and go to town. This handles multi-fork,
# setsid, and shutting down stdin/out/err.
Process.daemon(true)
Chef::Log.debug("[#{new_resource}] Daemonized")
# Daemonized, set up process environment.
Dir.chdir(new_resource.directory)
Chef::Log.debug("[#{new_resource}] Directory changed to #{new_resource.directory}")
ENV['HOME'] = Dir.home(new_resource.user)
new_resource.environment.each do |key, val|
ENV[key.to_s] = val.to_s
end
Chef::Log.debug("[#{new_resource}] Process environment configured")
IO.write(pid_file, Process.pid)
Chef::Log.debug("[#{new_resource}] PID written to #{pid_file}")
ent = Etc.getpwnam(new_resource.user)
if Process.euid != ent.uid || Process.egid != ent.gid
Process.initgroups(ent.name, ent.gid)
Process::GID.change_privilege(ent.gid) if Process.egid != ent.gid
Process::UID.change_privilege(ent.uid) if Process.euid != ent.uid
end
Chef::Log.debug("[#{new_resource}] Changed privs to #{new_resource.user} (#{ent.uid}:#{ent.gid})")
# Split the command so we don't get an extra sh -c.
Chef::Log.debug("[#{new_resource}] Execing #{new_resource.command}")
Kernel.exec(*Shellwords.split(new_resource.command))
# Just in case, bail out.
exit!
# :nocov:
end
Chef::Log.debug("[#{new_resource}] Started.")
end
def action_stop
return unless pid
Chef::Log.debug("[#{new_resource}] Stopping with #{new_resource.stop_signal}. Current PID is #{pid.inspect}.")
Process.kill(new_resource.stop_signal, pid)
::File.unlink(pid_file)
end
def action_restart
return if options['never_restart']
action_stop
action_start
end
def action_reload
return if options['never_reload']
return unless pid
Chef::Log.debug("[#{new_resource}] Reloading with #{new_resource.reload_signal}. Current PID is #{pid.inspect}.")
Process.kill(new_resource.reload_signal, pid)
end
def pid
return nil unless ::File.exist?(pid_file)
pid = IO.read(pid_file).to_i
begin
# Check if the PID is running.
Process.kill(0, pid)
pid
rescue Errno::ESRCH
nil
end
end
private
def service_resource
# Intentionally not implemented.
raise NotImplementedError
end
def enable_service
end
# Write all major service parameters to a file so that if they change, we
# can restart the service. This also makes debuggin a bit easier so you
# can still see what it thinks it was starting without sifting through
# piles of debug output.
def create_service
service_template(run_file, 'dummy.json.erb')
end
def disable_service
end
# Delete the tracking file.
def destroy_service
file run_file do
action :delete
end
file pid_file do
action :delete
end
end
# Path to the run parameters tracking file.
def run_file
"/var/run/#{new_resource.service_name}.json"
end
# Path to the PID file.
def pid_file
"/var/run/#{new_resource.service_name}.pid"
end
end
end
end

View File

@ -1,150 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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/util/file_edit'
require 'poise_service/service_providers/base'
module PoiseService
module ServiceProviders
class Inittab < Base
provides(:inittab)
def self.provides_auto?(node, resource)
::File.exist?('/etc/inittab')
end
def pid
IO.read(pid_file).to_i if ::File.exist?(pid_file)
end
# Don't try to stop when disabling because we can't.
def action_disable
disable_service
notifying_block do
destroy_service
end
end
def action_start
Chef::Log.debug("[#{new_resource}] Inittab services are always started.")
end
def action_stop
raise NotImplementedError.new("[#{new_resource}] Inittab services cannot be stopped")
end
def action_restart
return if options['never_restart']
# Just kill it and let init restart it.
Process.kill(new_resource.stop_signal, pid) if pid
end
def action_reload
return if options['never_reload']
Process.kill(new_resource.reload_signal, pid) if pid
end
private
def service_resource
# Intentionally not implemented.
raise NotImplementedError
end
def enable_service
end
def disable_service
end
def create_service
# Sigh scoping.
pid_file_ = pid_file
# Inittab only allows 127 characters for the command, so cram stuff in
# a file. Writing to a file is gross, but so is using inittab so ¯\_(ツ)_/¯.
service_template("/sbin/poise_service_#{new_resource.service_name}", 'inittab.sh.erb') do
mode '755'
variables.update(
pid_file: pid_file_,
)
end
# Add to inittab.
edit_inittab do |content|
inittab_line = "#{service_id}:2345:respawn:/sbin/poise_service_#{new_resource.service_name}"
if content =~ /^# #{Regexp.escape(service_tag)}$/
# Existing line, update in place.
content.gsub!(/^(# #{Regexp.escape(service_tag)}\n)(.*)$/, "\\1#{inittab_line}")
else
# Add to the end.
content << "# #{service_tag}\n#{inittab_line}\n"
end
end
end
def destroy_service
# Remove from inittab.
edit_inittab do |content|
content.gsub!(/^# #{Regexp.escape(service_tag)}\n.*?\n$/, '')
end
file "/sbin/poise_service_#{new_resource.service_name}" do
action :delete
end
file pid_file do
action :delete
end
end
# The shortened ID because sysvinit only allows 4 characters.
def service_id
# This is a terrible hash, but it should be good enough.
options['service_id'] || begin
sum = new_resource.service_name.sum(20).to_s(36)
if sum.length < 4
'p' + sum
else
sum
end
end
end
# Tag to put in a comment in inittab for tracking.
def service_tag
"poise_service(#{new_resource.service_name})"
end
def pid_file
options['pid_file'] || "/var/run/#{new_resource.service_name}.pid"
end
def edit_inittab(&block)
inittab = IO.read('/etc/inittab')
original_inittab = inittab.dup
block.call(inittab)
if inittab != original_inittab
file '/etc/inittab' do
content inittab
end
execute 'telinit q'
end
end
end
end
end

View File

@ -1,83 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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 'poise_service/service_providers/base'
module PoiseService
module ServiceProviders
class Systemd < Base
include Chef::Mixin::ShellOut
provides(:systemd)
# @api private
def self.provides_auto?(node, resource)
# Don't allow systemd under docker, it won't work in most cases.
return false if node['virtualization'] && %w{docker lxc}.include?(node['virtualization']['system'])
service_resource_hints.include?(:systemd)
end
# @api private
def self.default_inversion_options(node, resource)
super.merge({
# Automatically reload systemd on changes.
auto_reload: true,
})
end
def pid
cmd = shell_out(%w{systemctl status} + [new_resource.service_name])
if !cmd.error? && cmd.stdout.include?('Active: active (running)') && md = cmd.stdout.match(/Main PID: (\d+)/)
md[1].to_i
else
nil
end
end
private
def service_resource
super.tap do |r|
r.provider(Chef::Provider::Service::Systemd)
end
end
def systemctl_daemon_reload
execute 'systemctl daemon-reload' do
action :nothing
user 'root'
end
end
def create_service
reloader = systemctl_daemon_reload
service_template("/etc/systemd/system/#{new_resource.service_name}.service", 'systemd.service.erb') do
notifies :run, reloader, :immediately if options['auto_reload']
variables.update(auto_reload: options['auto_reload'])
end
end
def destroy_service
file "/etc/systemd/system/#{new_resource.service_name}.service" do
action :delete
end
end
end
end
end

View File

@ -1,91 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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 'poise_service/service_providers/base'
module PoiseService
module ServiceProviders
class Sysvinit < Base
provides(:sysvinit)
def self.provides_auto?(node, resource)
[:debian, :redhat, :invokercd].any? {|name| service_resource_hints.include?(name) }
end
def pid
IO.read(pid_file).to_i if ::File.exist?(pid_file)
end
private
def service_resource
super.tap do |r|
r.provider(case node['platform_family']
when 'debian'
Chef::Provider::Service::Debian
when 'rhel'
Chef::Provider::Service::Redhat
else
# This will explode later in the template, but better than nothing for later.
Chef::Provider::Service::Init
end)
r.init_command(script_path)
end
end
def create_service
# Split the command into the binary and its arguments. This is for
# start-stop-daemon since it treats those differently.
parts = new_resource.command.split(/ /, 2)
daemon = ENV['PATH'].split(/:/)
.map {|path| ::File.absolute_path(parts[0], path) }
.find {|path| ::File.exist?(path) } || parts[0]
# Sigh scoping.
pid_file_ = pid_file
# Render the service template
service_template(script_path, 'sysvinit.sh.erb') do
mode '755'
variables.update(
daemon: daemon,
daemon_options: parts[1].to_s,
pid_file: pid_file_,
pid_file_external: !!options['pid_file'],
platform_family: node['platform_family'],
)
end
end
def destroy_service
file script_path do
action :delete
end
file pid_file do
action :delete
end
end
def script_path
options['script_path'] || "/etc/init.d/#{new_resource.service_name}"
end
def pid_file
options['pid_file'] || "/var/run/#{new_resource.service_name}.pid"
end
end
end
end

View File

@ -1,128 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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.
#
# Used in the template.
require 'shellwords'
require 'chef/mixin/shell_out'
require 'poise_service/error'
require 'poise_service/service_providers/base'
module PoiseService
module ServiceProviders
class Upstart < Base
include Chef::Mixin::ShellOut
provides(:upstart)
def self.provides_auto?(node, resource)
# Don't allow upstart under docker, it won't work.
return false if node['virtualization'] && %w{docker lxc}.include?(node['virtualization']['system'])
service_resource_hints.include?(:upstart)
end
# True restart in Upstart preserves the original config data, we want the
# more obvious behavior like everything else in the world that restart
# would re-read the updated config file. Use stop+start to get this
# behavior. http://manpages.ubuntu.com/manpages/raring/man8/initctl.8.html
def action_restart
return if options['never_restart']
action_stop
action_start
end
# Shim out reload if we have a version that predates reload support.
def action_reload
return if options['never_reload']
if !upstart_features[:reload_signal] && new_resource.reload_signal != 'HUP'
if options[:reload_shim]
Process.kill(new_resource.reload_signal, pid)
else
check_reload_signal!
end
else
super
end
end
def pid
cmd = shell_out(%w{initctl status} + [new_resource.service_name])
if !cmd.error? && md = cmd.stdout.match(/process (\d+)/)
md[1].to_i
else
nil
end
end
private
def service_resource
super.tap do |r|
r.provider(Chef::Provider::Service::Upstart)
end
end
def create_service
check_reload_signal!
# Set features so it will be a closure below.
features = upstart_features
service_template("/etc/init/#{new_resource.service_name}.conf", 'upstart.conf.erb') do
variables.update(
upstart_features: features,
)
end
end
def destroy_service
file "/etc/init/#{new_resource.service_name}.conf" do
action :delete
end
end
def upstart_version
cmd = shell_out(%w{initctl --version})
if !cmd.error? && md = cmd.stdout.match(/upstart ([^)]+)\)/)
md[1]
else
'0'
end
end
def upstart_features
@upstart_features ||= begin
upstart_ver = Gem::Version.new(upstart_version)
versions_added = {
kill_signal: '1.3',
reload_signal: '1.10',
setuid: '1.4',
}
versions_added.inject({}) do |memo, (feature, version)|
memo[feature] = Gem::Requirement.create(">= #{version}").satisfied_by?(upstart_ver)
memo
end
end
end
def check_reload_signal!
if !options['reload_shim'] && !upstart_features[:reload_signal] && new_resource.reload_signal != 'HUP'
raise Error.new("Upstart #{upstart_version} only supports HUP for reload, to use the shim please set the 'reload_shim' options for #{new_resource.to_s}")
end
end
end
end
end

View File

@ -1,45 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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 'pathname'
module PoiseService
# Utility methods for PoiseService.
#
# @api public
# @since 1.0.0
module Utils
# Methods are also available as module-level methods as well as a mixin.
extend self
# Common segments to ignore
COMMON_SEGMENTS = %w{var www current etc}.inject({}) {|memo, seg| memo[seg] = true; memo }
# Parse the service name from a path. Look at the last component of the
# path, ignoring some common names.
#
# @param path [String] Path to parse.
# @return [String]
# @example
# attribute(:service_name, kind_of: String, default: lazy { PoiseService::Utils.parse_service_name(path) })
def parse_service_name(path)
parts = Pathname.new(path).each_filename.to_a.reverse!
# Find the last segment not in common segments, fall back to the last segment.
parts.find {|seg| !COMMON_SEGMENTS[seg] } || parts.first
end
end
end

View File

@ -1,20 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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.
#
module PoiseService
VERSION = '1.1.1'
end

View File

@ -1,19 +0,0 @@
#
# Copyright 2015-2016, Noah Kantrowitz
#
# 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.
#
raise 'Halite is not compatible with no_lazy_load false, please set no_lazy_load true in your Chef configuration file.' unless Chef::Config[:no_lazy_load]
$LOAD_PATH << File.expand_path('../../files/halite_gem', __FILE__)
require "poise_service/cheftie"

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
<%= {command: @command,
directory: @directory,
environment: @environment,
name: @name,
reload_signal: @reload_signal,
stop_signal: @stop_signal,
user: @user}.to_json %>

View File

@ -1,15 +0,0 @@
#!/bin/sh
exec /opt/chef/embedded/bin/ruby <<EOH
require 'etc'
IO.write("<%= @pid_file %>", Process.pid)
Dir.chdir("<%= @directory %>")
ent = Etc.getpwnam("<%= @user %>")
if Process.euid != ent.uid || Process.egid != ent.gid
Process.initgroups(ent.name, ent.gid)
Process::GID.change_privilege(ent.gid) if Process.egid != ent.gid
Process::UID.change_privilege(ent.uid) if Process.euid != ent.uid
end
(ENV["HOME"] = Dir.home("<%= @user %>")) rescue nil
<%= @environment.map {|key, value| "ENV[\"#{key}\"] = \"#{value}\"" }.join("; ") %>
exec(*<%= Shellwords.split(@command).inspect %>)
EOH

View File

@ -1,13 +0,0 @@
[Unit]
Description=<%= @name %>
[Service]
Environment=<%= @environment.map {|key, val| %Q{"#{key}=#{val}"} }.join(' ') %>
ExecStart=<%= @command %>
ExecReload=/bin/kill -<%= @reload_signal %> $MAINPID
KillSignal=<%= @stop_signal %>
User=<%= @user %>
WorkingDirectory=<%= @directory %>
[Install]
WantedBy=multi-user.target

View File

@ -1,190 +0,0 @@
#!/bin/sh
# Init script for <%= @name %> generated by poise-service
#
### BEGIN INIT INFO
# Provides: <%= @name %>
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Init script for <%= @name %>
# Description: Init script for <%= @name %>
### END INIT INFO
<%- if @platform_family == 'debian' -%>
. /lib/lsb/init-functions
_start() {
start-stop-daemon --start --quiet --background \
--pidfile "<%= @pid_file %>"<% unless @pid_file_external %> --make-pidfile<% end %> \
--chuid "<%= @user %>" --chdir "<%= @directory %>" \
--exec "<%= @daemon %>" -- <%= @daemon_options %>
}
_stop() {
start-stop-daemon --stop --quiet --pidfile "<%= @pid_file %>" --user "<%= @user %>" --signal "<%= @stop_signal %>"
}
_status() {
status_of_proc -p "<%= @pid_file %>" "<%= @daemon %>" "<%= @name %>"
}
_reload() {
start-stop-daemon --stop --quiet --pidfile "<%= @pid_file %>" --user "<%= @user %>" --signal "<%= @reload_signal %>"
}
<%- else -%>
_start() {
<%# Implementing this using RedHat's bash helpers is too painful. Sorry. %>
<%# See dummy.rb for a more commented version of this code. %>
/opt/chef/embedded/bin/ruby <<EOH
require 'etc'
pid_file = <%= @pid_file.inspect %>
File.unlink(pid_file) if File.exist?(pid_file)
if Process.fork
sleep(1) until File.exist?(pid_file)
else
Process.daemon(true)
Dir.chdir(<%= @directory.inspect %>)
<%- unless @pid_file_external -%>
IO.write(pid_file, Process.pid)
<%- end -%>
ent = Etc.getpwnam(<%= @user.inspect %>)
if Process.euid != ent.uid || Process.egid != ent.gid
Process.initgroups(ent.name, ent.gid)
Process::GID.change_privilege(ent.gid) if Process.egid != ent.gid
Process::UID.change_privilege(ent.uid) if Process.euid != ent.uid
end
Kernel.exec(*<%= Shellwords.split(@command).inspect %>)
exit!
end
EOH
}
_stop() {
if [ -r "<%= @pid_file %>" ]; then
kill -<%= @stop_signal%> "$(cat "<%= @pid_file %>")"
else
return 0
fi
}
_status() {
if [ -r "<%= @pid_file %>" ]; then
kill -0 "$(cat "<%= @pid_file %>")"
else
return 1
fi
}
_reload() {
if [ -r "<%= @pid_file %>" ]; then
kill -<%= @reload_signal%> "$(cat "<%= @pid_file %>")"
else
return 1
fi
}
<%# Some functions to match LSB %>
log_daemon_msg() {
echo -n "$1"
}
log_progress_msg() {
echo -n "$1"
}
log_warning_msg() {
echo -n "$1"
}
log_failure_msg() {
echo -n "$1"
}
log_end_msg() {
if [ "$1" = 0 ]; then
echo " [ OK ]"
else
echo " [FAILED]"
fi
}
<%- end -%>
set -e
start() {
if _start
then
rc=0
sleep 1
if ! kill -0 "$(cat "<%= @pid_file %>")" >/dev/null 2>&1; then
log_failure_msg "<%= @name %> failed to start"
rc=1
fi
else
rc=1
fi
if [ "$rc" -eq 0 ]; then
log_end_msg 0
else
log_end_msg 1
rm -f "<%= @pid_file %>"
fi
}
<%- @environment.each do |key, val| -%>
export <%= key %>="<%= val %>"
<%- end -%>
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
case "$1" in
start)
log_daemon_msg "Starting <%= @name %>"
if [ -s "<%= @pid_file %>" ] && kill -0 "$(cat "<%= @pid_file %>")" >/dev/null 2>&1; then
log_progress_msg "apparently already running"
log_end_msg 0
exit 0
fi
start
;;
stop)
log_daemon_msg "Stopping <%= @name %>"
_stop
log_end_msg "$?"
rm -f "<%= @pid_file %>"
;;
reload|force-reload)
log_daemon_msg "Reloading <%= @name %>"
_reload
log_end_msg "$?"
;;
restart)
set +e
log_daemon_msg "Restarting <%= @name %>"
if [ -s "<%= @pid_file %>" ] && kill -0 "$(cat "<%= @pid_file %>")" >/dev/null 2>&1; then
_stop || true
sleep 1
else
log_warning_msg "<%= @name %> not running, attempting to start."
rm -f "<%= @pid_file %>"
fi
start
;;
status)
set +e
_status
exit $?
;;
*)
echo "Usage: /etc/init.d/<%= @name %> {start|stop|reload|force-reload|restart|status}"
exit 1
esac
exit 0

View File

@ -1,49 +0,0 @@
# <%= @name %> generated by poise-service for <%= @new_resource.to_s %>
description "<%= @name %>"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
respawn limit 10 5
umask 022
chdir <%= @directory %>
<%- @environment.each do |key, val| -%>
env <%= key %>="<%= val %>"
<%- end -%>
<%- if @upstart_features[:setuid] -%>
setuid <%= @user %>
<%- end -%>
<%- if @upstart_features[:kill_signal] -%>
kill signal <%= @stop_signal %>
<%- end -%>
<%- if @upstart_features[:reload_signal] -%>
reload signal <%= @reload_signal %>
<%- end -%>
<%- if @upstart_features[:setuid] -%>
exec <%= @command %>
<%- else -%>
script
exec /opt/chef/embedded/bin/ruby <<EOH
require 'etc'
ent = Etc.getpwnam(<%= @user.inspect %>)
if Process.euid != ent.uid || Process.egid != ent.gid
Process.initgroups(ent.name, ent.gid)
Process::GID.change_privilege(ent.gid) if Process.egid != ent.gid
Process::UID.change_privilege(ent.uid) if Process.euid != ent.uid
end
ENV["HOME"] = Dir.home(<%= @user.inspect %>) rescue nil
exec(*<%= Shellwords.split(@command).inspect %>)
EOH
end script
<%- end -%>
<%- if !@upstart_features[:kill_signal] && @stop_signal != 'TERM' -%>
pre-stop script
PID=`initctl status <%= @name %> | sed 's/^.*process \([0-9]*\)$/\1/'`
if [ -n "$PID" ]; then
kill -<%= @stop_signal %> "$PID"
fi
end script
<%- end -%>

View File

@ -1,163 +0,0 @@
# Changelog
## v2.6.0
* New backwards-compatibility helper: `Poise::Backports::VERIFY_PATH`. Use it
like `verify "myapp -t #{Poise::Backports::VERIFY_PATH}" if defined?(verify)`
for backwards-compatible usage of file verifications.
* Fixed Poise's implementation of lazy defaults to more closely match Chef's
even when both are used in conjunction. Lazy defaults will no longer be
evaluated when setting a value or getting an existing non-default value.
## v2.5.0
* New property for inversion resources: `provider_no_auto`. Set one or more
provider names that will be ignored for automatic resolution for that instance.
* Support `variables` as an alias for `options` in template content properties
to match the `template` resource.
* Template content properties are no longer validated after creation for
non-default actions.
* Formalize the extra-verbose logging mode for Poise and expose it via helpers.
* Extra-verbose logging mode can now be enabled by creating a `/poise_debug` file.
* New helper: `poise_shell_out`. Like normal `shell_out` but sets group and
environment variables automatically to better defaults.
## v2.4.0
* Added return value to `Container#register_subresource` to track if the resource
was already added.
* Improve inspect output for subresources and containers.
* Ensure notifications work with subresources.
* Inversion providers process name equivalences.
## v2.3.2
* Improve handling of deeply nested subresources.
## v2.3.1
* Ensure a container with a parent link to its own type doesn't use self as the
default parent.
* Improve handling of `load_current_resource` in providers that call it via
`super`.
## v2.3.0
* New helper: `ResourceSubclass`, a helper for subclassing a resource while
still using the providers as the base class.
* New feature: Non-default containers. Use `container_default: false` to mark
a container class as ineligible for default lookup.
* New feature: parent attribute defaults. You can set a `parent_default` to
provide a default value for the parent of a resource. This supports the
`lazy { }` helper as with normal default values.
* New feature: use `forced_keys: [:name]` on an option collector property to
force keys that would otherwise be clobbered by resource methods.
* Can enable verbose logging mode via a node attribute in addition to an
environment variable.
## v2.2.3
* Add `ancestor_send` utility method for use in other helpers.
* Improve subresource support for use in mixins.
## v2.2.2
* Fix 2.2.1 for older versions of Chef.
## v2.2.1
* Fixed delayed notifications inside `notifying_block`.
* Default actions as expected within LWRPs.
## v2.2.0
* Compatibility with Chef 12.4.1 and Chefspec 4.3.0.
* New helper `ResourceCloning`: Disables resource cloning between Poise-based
resources. This is enabled by default.
* Subresource parent references can be set to nil.
## v2.1.0
* Compatibility with Chef 12.4.
* Add `#property` as an alias for `#attribute` in resources. This provides
forward compatibility with future versions of Chef.
* Freeze default resource attribute values. **This may break your code**,
however this is not a major release because any code broken by this change
was itself already a bug.
## v2.0.1
* Make the ChefspecHelpers helper a no-op if chefspec is not already loaded.
* Fix for finding the correct cookbook for a file when using vendored gems.
* New flag for the OptionCollector helper, `parser`:
```ruby
class Resource < Chef::Resource
include Poise
attribute(:options, option_collector: true, parser: proc {|val| parse(val) })
def parse(val)
{name: val}
end
end
```
* Fix for a possible infinite loop when using `ResourceProviderMixin` in a nested
module structure.
## v2.0.0
Major overhaul! Poise is now a Halite gem/cookbook. New helpers:
* ChefspecMatchers Automatically create Chefspec matchers for Poise resources.
* DefinedIn Track which file (and cookbook) a resource or provider is defined in.
* Fused Experimental support for defining provider actions in the resource class.
* Inversion Support for end-user dependency inversion with providers.
All helpers are compatible with Chef >= 12.0. Chef 11 is now deprecated, if you
need to support Chef 11 please continue to use Poise 1.
## v1.0.12
* Correctly propagate errors from inside notifying_block.
## v1.0.10
* Fixes an issue with the LWRPPolyfill helper and false values.
## v1.0.8
* Delayed notifications from nested converges will still only run at the end of
the main converge.
## v1.0.6
* The include_recipe helper now works correctly when used at compile time.
## v1.0.4
* Redeclaring a template attribute with the same name as a parent class will
inherit its options.
## v1.0.2
* New template attribute pattern.
```ruby
attribute(:config, template: true)
...
resource 'name' do
config_source 'template.erb'
end
...
new_resource.config_content
```
## v1.0.0
* Initial release!

View File

@ -1,233 +0,0 @@
# Poise
[![Build Status](https://img.shields.io/travis/poise/poise.svg)](https://travis-ci.org/poise/poise)
[![Gem Version](https://img.shields.io/gem/v/poise.svg)](https://rubygems.org/gems/poise)
[![Cookbook Version](https://img.shields.io/cookbook/v/poise.svg)](https://supermarket.chef.io/cookbooks/poise)
[![Coverage](https://img.shields.io/codecov/c/github/poise/poise.svg)](https://codecov.io/github/poise/poise)
[![Gemnasium](https://img.shields.io/gemnasium/poise/poise.svg)](https://gemnasium.com/poise/poise)
[![License](https://img.shields.io/badge/license-Apache_2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
## What is Poise?
The poise cookbook is a set of libraries for writing reusable cookbooks. It
provides helpers for common patterns and a standard structure to make it easier to create flexible cookbooks.
## Writing your first resource
Rather than LWRPs, Poise promotes the idea of using normal, or "heavy weight"
resources, while including helpers to reduce much of boilerplate needed for this. Each resource goes in its own file under `libraries/` named to match
the resource, which is in turn based on the class name. This means that the file `libraries/my_app.rb` would contain `Chef::Resource::MyApp` which maps to the resource `my_app`.
An example of a simple shell to start from:
```ruby
require 'poise'
require 'chef/resource'
require 'chef/provider'
module MyApp
class Resource < Chef::Resource
include Poise
provides(:my_app)
actions(:enable)
attribute(:path, kind_of: String)
# Other attribute definitions.
end
class Provider < Chef::Provider
include Poise
provides(:my_app)
def action_enable
notifying_block do
... # Normal Chef recipe code goes here
end
end
end
end
```
Starting from the top, first we require the libraries we will be using. Then we
create a module to hold our resource and provider. If your cookbook declares
multiple resources and/or providers, you might want additional nesting here.
Then we declare the resource class, which inherits from `Chef::Resource`. This
is similar to the `resources/` file in an LWRP, and a similar DSL can be used.
We then include the `Poise` mixin to load our helpers, and then call
`provides(:my_app)` to tell Chef this class will implement the `my_app`
resource. Then we use the familiar DSL, though with a few additions we'll cover
later.
Then we declare the provider class, again similar to the `providers/` file in an
LWRP. We include the `Poise` mixin again to get access to all the helpers and
call `provides()` to tell Chef what provider this is. Rather than use the
`action :enable do ... end` DSL from LWRPs, we just define the action method
directly. The implementation of action comes from a block of recipe code
wrapped with `notifying_block` to capture changes in much the same way as
`use_inline_resources`, see below for more information about all the features of
`notifying_block`.
We can then use this resource like any other Chef resource:
```ruby
my_app 'one' do
path '/tmp'
end
```
## Helpers
While not exposed as a specific method, Poise will automatically set the
`resource_name` based on the class name.
### Notifying Block
As mentioned above, `notifying_block` is similar to `use_inline_resources` in LWRPs. Any Chef resource created inside the block will be converged in a sub-context and if any have updated it will trigger notifications on the current resource. Unlike `use_inline_resources`, resources inside the sub-context can still see resources outside of it, with lookups propagating up sub-contexts until a match is found. Also any delayed notifications are scheduled to run at the end of the main converge cycle, instead of the end of this inner converge.
This can be used to write action methods using the normal Chef recipe DSL, while still offering more flexibility through subclassing and other forms of code reuse.
### Include Recipe
In keeping with `notifying_block` to implement action methods using the Chef DSL, Poise adds an `include_recipe` helper to match the method of the same name in recipes. This will load and converge the requested recipe.
### Resource DSL
To make writing resource classes easier, Poise exposes a DSL similar to LWRPs for defining actions and attributes. Both `actions` and
`default_action` are just like in LWRPs, though `default_action` is rarely needed as the first action becomes the default. `attribute` is also available just like in LWRPs, but with some enhancements noted below.
One notable difference over the standard DSL method is that Poise attributes
can take a block argument.
#### Template Content
A common pattern with resources is to allow passing either a template filename or raw file content to be used in a configuration file. Poise exposes a new attribute flag to help with this behavior:
```ruby
attribute(:name, template: true)
```
This creates four methods on the class, `name_source`, `name_cookbook`,
`name_content`, and `name_options`. If the name is set to `''`, no prefix is applied to the function names. The content method can be set directly, but if not set and source is set, then it will render the template and return it as a string. Default values can also be set for any of these:
```ruby
attribute(:name, template: true, default_source: 'app.cfg.erb',
default_options: {host: 'localhost'})
```
As an example, you can replace this:
```ruby
if new_resource.source
template new_resource.path do
source new_resource.source
owner 'app'
group 'app'
variables new_resource.options
end
else
file new_resource.path do
content new_resource.content
owner 'app'
group 'app'
end
end
```
with simply:
```ruby
file new_resource.path do
content new_resource.content
owner 'app'
group 'app'
end
```
As the content method returns the rendered template as a string, this can also
be useful within other templates to build from partials.
#### Lazy Initializers
One issue with Poise-style resources is that when the class definition is executed, Chef hasn't loaded very far so things like the node object are not
yet available. This means setting defaults based on node attributes does not work directly:
```ruby
attribute(:path, default: node['myapp']['path'])
...
NameError: undefined local variable or method 'node'
```
To work around this, Poise extends the idea of lazy initializers from Chef recipes to work with resource definitions as well:
```ruby
attribute(:path, default: lazy { node['myapp']['path'] })
```
These initializers are run in the context of the resource object, allowing
complex default logic to be moved to a method if desired:
```ruby
attribute(:path, default: lazy { my_default_path })
def my_default_path
...
end
```
#### Option Collector
Another common pattern with resources is to need a set of key/value pairs for
configuration data or options. This can done with a simple Hash, but an option collector attribute can offer a nicer syntax:
```ruby
attribute(:mydata, option_collector: true)
...
my_app 'name' do
mydata do
key1 'value1'
key2 'value2'
end
end
```
This will be converted to `{key1: 'value1', key2: 'value2'}`. You can also pass a Hash to an option collector attribute just as you would with a normal attribute.
## Debugging Poise
Poise has its own extra-verbose level of debug logging that can be enabled in
three different ways. You can either set the environment variable `$POISE_DEBUG`,
set a node attribute `node['POISE_DEBUG']`, or touch the file `/POISE_DEBUG`.
You will see a log message `Extra verbose logging enabled` at the start of the
run to confirm Poise debugging has been enabled. Make sure you also set Chef's
log level to `debug`, usually via `-l debug` on the command line.
## Upgrading from Poise 1.x
The biggest change when upgrading from Poise 1.0 is that the mixin is no longer
loaded automatically. You must add `require 'poise'` to your code is you want to
load it, as you would with normal Ruby code outside of Chef. It is also highly
recommended to add `provides(:name)` calls to your resources and providers, this
will be required in Chef 13 and will display a deprecation warning if you do
not. This also means you can move your code out of the `Chef` module namespace
and instead declare it in your own namespace. An example of this is shown above.
## Sponsors
The Poise test server infrastructure is generously sponsored by [Rackspace](https://rackspace.com/). Thanks Rackspace!
## License
Copyright 2013-2015, Noah Kantrowitz
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.

View File

@ -1,107 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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/provider'
require 'chef/resource'
require 'poise/utils/resource_provider_mixin'
module Poise
include Poise::Utils::ResourceProviderMixin
autoload :Backports, 'poise/backports'
autoload :Helpers, 'poise/helpers'
autoload :NOT_PASSED, 'poise/backports/not_passed'
autoload :Provider, 'poise/provider'
autoload :Resource, 'poise/resource'
autoload :Subcontext, 'poise/subcontext'
autoload :Utils, 'poise/utils'
autoload :VERSION, 'poise/version'
# Check if Poise's extra debugging output is enabled. This produces a *lot*
# of logging.
#
# @param node [Chef::Node, Chef::RunContext] Optional node to check for
# attributes. If not given, Chef.node is used instead.
# @return [Boolean]
def self.debug?(node=nil)
node = node.node if node.is_a?(Chef::RunContext)
node ||= Chef.node if defined?(Chef.node)
@debug_file_upper = ::File.exist?('/POISE_DEBUG') unless defined?(@debug_file_upper)
@debug_file_lower = ::File.exist?('/poise_debug') unless defined?(@debug_file_lower)
!!(
(ENV['POISE_DEBUG'] && ENV['POISE_DEBUG'] != 'false') ||
(ENV['poise_debug'] && ENV['poise_debug'] != 'false') ||
(node && node['POISE_DEBUG']) ||
(node && node['poise_debug']) ||
@debug_file_upper ||
@debug_file_lower
)
end
# Log a message only if Poise's extra debugging output is enabled.
#
# @see #debug?
# @param msg [String] Log message.
# @return [void]
def self.debug(msg)
Chef::Log.debug(msg) if debug?
end
end
# Callable form to allow passing in options:
# include Poise(ParentResource)
# include Poise(parent: ParentResource)
# include Poise(container: true)
def Poise(options={})
# Allow passing a class as a shortcut
if options.is_a?(Class)
options = {parent: options}
end
# Create a new anonymous module
mod = Module.new
# Fake the name.
mod.define_singleton_method(:name) do
super() || 'Poise'
end
mod.define_singleton_method(:included) do |klass|
super(klass)
# Pull in the main helper to cover most of the needed logic.
klass.class_exec { include Poise }
# Set the defined_in values as needed.
klass.poise_defined!(caller)
# Resource-specific options.
if klass < Chef::Resource
klass.poise_subresource(options[:parent], options[:parent_optional], options[:parent_auto]) if options[:parent]
klass.poise_subresource_container(options[:container_namespace], options[:container_default]) if options[:container]
klass.poise_fused if options[:fused]
klass.poise_inversion(options[:inversion_options_resource]) if options[:inversion]
end
# Provider-specific options.
if klass < Chef::Provider
klass.poise_inversion(options[:inversion], options[:inversion_attribute]) if options[:inversion]
end
end
mod
end
# Display a message if poise_debug is enabled. Off in ChefSpec so I don't get
# extra logging stuff that I don't care about.
Poise.debug('[Poise] Extra verbose logging enabled') unless defined?(ChefSpec)

View File

@ -1,28 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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.
#
module Poise
# Backported features from Chef to be able to use them with older versions.
#
# @since 2.3.0
module Backports
autoload :NOT_PASSED, 'poise/backports/not_passed'
autoload :VERIFY_PATH, 'poise/backports/verify_path'
end
autoload :NOT_PASSED, 'poise/backports/not_passed'
end

View File

@ -1,52 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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.
#
begin
require 'chef/constants'
rescue LoadError
# This space left intentionally blank.
end
module Poise
module Backports
# A sentinel value for optional arguments where nil is a valid value.
# @since 2.3.0
# @!parse NOT_PASSED = Object.new
NOT_PASSED = if defined?(Chef::NOT_PASSED)
Chef::NOT_PASSED
else
# Copyright 2015, Chef Software Inc.
# Used under Apache License, Version 2.0.
Object.new.tap do |not_passed|
def not_passed.to_s
"NOT_PASSED"
end
def not_passed.inspect
to_s
end
not_passed.freeze
end
end
end
# An alias to {Backports::NOT_PASSED} to avoid typing so much.
#
# @since 2.3.0
# @see Backports::NOT_PASSED
NOT_PASSED = Backports::NOT_PASSED
end

View File

@ -1,33 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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.
#
module Poise
module Backports
# The correct interpolation key for any version of Chef.
# @since 2.6.0
# @example
# file '/path' do
# content my_content
# verify "myapp -t #{Poise::Backports::VERIFY_PATH}"
# end
VERIFY_PATH = if Gem::Version.create(Chef::VERSION) < Gem::Version.create('12.5.0')
'%{file}'
else
'%{path}'
end
end
end

View File

@ -1,24 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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.
#
module Poise
# Base exception class for Poise errors.
#
# @since 2.0.0
class Error < Exception
end
end

View File

@ -1,35 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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.
#
module Poise
module Helpers
autoload :ChefspecMatchers, 'poise/helpers/chefspec_matchers'
autoload :DefinedIn, 'poise/helpers/defined_in'
autoload :Fused, 'poise/helpers/fused'
autoload :IncludeRecipe, 'poise/helpers/include_recipe'
autoload :Inversion, 'poise/helpers/inversion'
autoload :LazyDefault, 'poise/helpers/lazy_default'
autoload :LWRPPolyfill, 'poise/helpers/lwrp_polyfill'
autoload :NotifyingBlock, 'poise/helpers/notifying_block'
autoload :OptionCollector, 'poise/helpers/option_collector'
autoload :ResourceCloning, 'poise/helpers/resource_cloning'
autoload :ResourceName, 'poise/helpers/resource_name'
autoload :ResourceSubclass, 'poise/helpers/resource_subclass'
autoload :Subresources, 'poise/helpers/subresources'
autoload :TemplateContent, 'poise/helpers/template_content'
end
end

View File

@ -1,92 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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.
#
# Not requiring chefspec or rspec/expectations since this code should only
# activate if they are already loaded.
require 'poise/helpers/lwrp_polyfill'
require 'poise/helpers/resource_name'
module Poise
module Helpers
# A resource mixin to register ChefSpec matchers for a resource
# automatically.
#
# If you are using the provides() form for naming resources, ensure that is
# set before declaring actions.
#
# @since 2.0.0
# @example Define a class
# class Chef::Resource::MyResource < Chef::Resource
# include Poise::Helpers::ChefspecMatchers
# actions(:run)
# end
# @example Use a matcher
# expect(chef_run).to run_my_resource('...')
module ChefspecMatchers
include Poise::Helpers::LWRPPolyfill::Resource
include Poise::Helpers::ResourceName
# Create a matcher for a given resource type and action. This is
# idempotent so if a matcher already exists, it will not be recreated.
#
# @api private
def self.create_matcher(resource, action)
# Check that we have everything we need.
return unless defined?(ChefSpec) && defined?(RSpec::Matchers) && resource
method = :"#{action}_#{resource}"
return if RSpec::Matchers.method_defined?(method)
RSpec::Matchers.send(:define_method, method) do |resource_name|
ChefSpec::Matchers::ResourceMatcher.new(resource, action, resource_name)
end
end
# @!classmethods
module ClassMethods
# Create a resource-level matcher for this resource.
#
# @see Resource::ResourceName.provides
def provides(name, *args, &block)
super(name, *args, &block)
ChefSpec.define_matcher(name) if defined?(ChefSpec)
# Call #actions here to grab any actions from a parent class.
actions.each do |action|
ChefspecMatchers.create_matcher(name, action)
end
end
# Create matchers for all declared actions.
#
# @see Resource::LWRPPolyfill.actions
def actions(*names)
super.tap do |actions|
actions.each do |action|
ChefspecMatchers.create_matcher(resource_name, action)
end if resource_name && resource_name != :resource && !names.empty?
end
end
def included(klass)
super
klass.extend ClassMethods
end
end
extend ClassMethods
end
end
end

View File

@ -1,111 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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 'poise/error'
require 'poise/utils'
module Poise
module Helpers
# A mixin to track where a resource or provider was defined. This can
# provide either the filename of the class or the cookbook it was defined in.
#
# @since 2.0.0
# @example
# class MyProvider < Chef::provider
# include Poise::Helpers::DefinedIn
#
# def action_create
# template '...' do
# # ...
# cookbook new_resource.poise_defined_in
# end
# end
# end
module DefinedIn
# Wrapper for {.poise_defined_in_cookbook} to pass the run context for you.
#
# @see .poise_defined_in_cookbook
# @param file [String, nil] Optional file path to check instead of the path
# this class was defined in.
# @return [String]
def poise_defined_in_cookbook(file=nil)
self.class.poise_defined_in_cookbook(run_context, file)
end
# @!classmethods
module ClassMethods
# The file this class or module was defined in, or nil if it isn't found.
#
# @return [String]
def poise_defined_in
raise Poise::Error.new("Unable to determine location of #{self.name}") unless @poise_defined_in
@poise_defined_in
end
# The cookbook this class or module was defined in. Can pass a file to
# check that instead.
#
# @param run_context [Chef::RunContext] Run context to check cookbooks in.
# @param file [String, nil] Optional file path to check instead of the
# path this class was defined in.
# @return [String]
def poise_defined_in_cookbook(run_context, file=nil)
file ||= poise_defined_in
Poise.debug("[#{self.name}] Checking cookbook name for #{file}")
Poise::Utils.find_cookbook_name(run_context, file).tap do |cookbook|
Poise.debug("[#{self.name}] found cookbook #{cookbook.inspect}")
end
end
# Record that the class/module was defined. Called automatically by Ruby
# for all normal cases.
#
# @param caller_array [Array<String>] A strack trace returned by #caller.
# @return [void]
def poise_defined!(caller_array)
# Only try to set this once.
return if @poise_defined_in
# Path to ignore, assumes Halite transformation which I'm not thrilled
# about.
poise_libraries = File.expand_path('../..', __FILE__)
# Parse out just the filenames.
caller_array = caller_array.map {|line| line.split(/:/, 2).first }
# Find the first non-poise line.
caller_path = caller_array.find do |line|
!line.start_with?(poise_libraries)
end
Chef::Log.debug("[#{self.name}] Recording poise_defined_in as #{caller_path}")
@poise_defined_in = caller_path
end
# @api private
def inherited(klass)
super
klass.poise_defined!(caller)
end
def included(klass)
super
klass.extend(ClassMethods)
klass.poise_defined!(caller)
end
end
extend ClassMethods
end
end
end

View File

@ -1,127 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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/provider'
module Poise
module Helpers
# Resource mixin to create "fused" resources where the resource and provider
# are implemented in the same class.
#
# @since 2.0.0
# @example
# class Chef::Resource::MyResource < Chef::Resource
# include Poise(fused: true)
# attribute(:path, kind_of: String)
# attribute(:message, kind_of: String)
# action(:run) do
# file new_resource.path do
# content new_resource.message
# end
# end
# end
module Fused
# Hack is_a? so that the DSL will consider this a Provider for the
# purposes of attaching enclosing_provider.
#
# @api private
# @param klass [Class]
# @return [Boolean]
def is_a?(klass)
if klass == Chef::Provider
# Lies, damn lies, and Ruby code.
true
else
super
end
end
# Hack provider_for_action so that the resource is also the provider.
#
# @api private
# @param action [Symbol]
# @return [Chef::Provider]
def provider_for_action(action)
provider(self.class.fused_provider_class) unless provider
super
end
# @!classmethods
module ClassMethods
# Define a provider action. The block should contain the usual provider
# code.
#
# @param name [Symbol] Name of the action.
# @param block [Proc] Action implementation.
# @example
# action(:run) do
# file '/temp' do
# user 'root'
# content 'temp'
# end
# end
def action(name, &block)
fused_actions[name.to_sym] = block
# Make sure this action is allowed, also sets the default if first.
if respond_to?(:actions)
actions(name.to_sym)
end
end
# Storage accessor for fused action blocks. Maps action name to proc.
#
# @api private
# @return [Hash<Symbol, Proc>]
def fused_actions
(@fused_actions ||= {})
end
# Create a provider class for the fused actions in this resource.
# Inherits from the fused provider class of the resource's superclass if
# present.
#
# @api private
# @return [Class]
def fused_provider_class
@fused_provider_class ||= begin
provider_superclass = begin
self.superclass.fused_provider_class
rescue NoMethodError
Chef::Provider
end
actions = fused_actions
class_name = self.name
Class.new(provider_superclass) do
include Poise
define_singleton_method(:name) { class_name + ' (fused)' }
actions.each do |action, block|
define_method(:"action_#{action}", &block)
end
end
end
end
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
end
end

View File

@ -1,62 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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 'poise/helpers/subcontext_block'
require 'poise/subcontext/runner'
module Poise
module Helpers
# A provider mixin to add #include_recipe that can be called from action
# methods.
#
# @since 2.0.0
module IncludeRecipe
include Poise::Helpers::SubcontextBlock
def include_recipe(*recipes)
loaded_recipes = []
subcontext = subcontext_block do
recipes.each do |recipe|
case recipe
when String
# Process normally
Chef::Log.debug("Loading recipe #{recipe} via include_recipe (poise)")
loaded_recipes += run_context.include_recipe(recipe)
when Proc
# Pretend its a block of recipe code
fake_recipe = Chef::Recipe.new(cookbook_name, new_resource.recipe_name, run_context)
fake_recipe.instance_eval(&recipe)
loaded_recipes << fake_recipe
end
end
end
# Converge the new context.
Poise::Subcontext::Runner.new(new_resource, subcontext).converge
collection = global_resource_collection
subcontext.resource_collection.each do |r|
Chef::Log.debug("Poise::IncludeRecipe: Adding #{r} to global collection #{collection.object_id}")
# Insert the local resource into the global context
collection.insert(r)
# Skip the iterator forward so we don't double-execute the inserted resource
# If running at compile time, the iterator is nil
collection.iterator.skip_forward if collection.iterator
end
loaded_recipes
end
end
end
end

View File

@ -1,414 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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/node'
require 'chef/node_map'
require 'chef/provider'
require 'chef/resource'
require 'poise/backports'
require 'poise/helpers/defined_in'
require 'poise/error'
require 'poise/helpers/inversion/options_resource'
require 'poise/utils/resource_provider_mixin'
module Poise
module Helpers
# A mixin for dependency inversion in Chef.
#
# @since 2.0.0
module Inversion
autoload :OptionsResource, 'poise/helpers/inversion/options_resource'
autoload :OptionsProvider, 'poise/helpers/inversion/options_provider'
include Poise::Utils::ResourceProviderMixin
# Resource implementation for {Poise::Helpers::Inversion}.
# @see Poise::Helpers::Inversion
module Resource
# @overload options(val=nil)
# Set or return provider options for all providers.
# @param val [Hash] Provider options to set.
# @return [Hash]
# @example
# my_resource 'thing_one' do
# options depends: 'thing_two'
# end
# @overload options(provider, val=nil)
# Set or return provider options for a specific provider.
# @param provider [Symbol] Provider to set for.
# @param val [Hash] Provider options to set.
# @return [Hash]
# @example
# my_resource 'thing_one' do
# options :my_provider, depends: 'thing_two'
# end
def options(provider=nil, val=nil)
key = :options
if !val && provider.is_a?(Hash)
val = provider
elsif provider
key = :"options_#{provider}"
end
set_or_return(key, val ? Mash.new(val) : val, kind_of: Hash, default: lazy { Mash.new })
end
# Allow setting the provider directly using the same names as the attribute
# settings.
#
# @param val [String, Symbol, Class, nil] Value to set the provider to.
# @return [Class]
# @example
# my_resource 'thing_one' do
# provider :my_provider
# end
def provider(val=nil)
if val && !val.is_a?(Class)
resource_names = [resource_name]
# If subclass_providers! might be in play, check for those names too.
resource_names.concat(self.class.subclass_resource_equivalents) if self.class.respond_to?(:subclass_resource_equivalents)
# Silly ruby tricks to find the first provider that exists and no more.
provider_class = resource_names.lazy.map {|name| Poise::Helpers::Inversion.provider_for(name, node, val) }.select {|x| x }.first
Poise.debug("[#{self}] Checking for an inversion provider for #{val}: #{provider_class && provider_class.name}")
val = provider_class if provider_class
end
super
end
# Set or return the array of provider names to be blocked from
# auto-resolution.
#
# @param val [String, Array<String>] Value to set.
# @return [Array<String>]
def provider_no_auto(val=nil)
# Coerce to an array.
val = Array(val).map(&:to_s) if val
set_or_return(:provider_no_auto, val, kind_of: Array, default: [])
end
# @!classmethods
module ClassMethods
# Options resource class.
attr_reader :inversion_options_resource_class
# Options provider class.
attr_reader :inversion_options_provider_class
# @overload inversion_options_resource()
# Return the options resource mode for this class.
# @return [Boolean]
# @overload inversion_options_resource(val)
# Set the options resource mode for this class. Set to true to
# automatically create an options resource. Defaults to true.
# @param val [Boolean] Enable/disable setting.
# @return [Boolean]
def inversion_options_resource(val=nil)
@poise_inversion_options_resource = val unless val.nil?
@poise_inversion_options_resource
end
# Create resource and provider classes for an options resource.
#
# @param name [String, Symbol] DSL name for the base resource.
# @return [void]
def create_inversion_options_resource!(name)
enclosing_class = self
options_resource_name = :"#{name}_options"
# Create the resource class.
@inversion_options_resource_class = Class.new(Chef::Resource) do
include Poise::Helpers::Inversion::OptionsResource
define_singleton_method(:name) do
"#{enclosing_class}::OptionsResource"
end
define_singleton_method(:inversion_resource_class) do
enclosing_class
end
provides(options_resource_name)
inversion_resource(name)
end
# Create the provider class.
@inversion_options_provider_class = Class.new(Chef::Provider) do
include Poise::Helpers::Inversion::OptionsProvider
define_singleton_method(:name) do
"#{enclosing_class}::OptionsProvider"
end
define_singleton_method(:inversion_resource_class) do
enclosing_class
end
provides(options_resource_name)
end
end
# Wrap #provides() to create an options resource if desired.
#
# @param name [Symbol] Resource name
# return [void]
def provides(name, *args, &block)
create_inversion_options_resource!(name) if inversion_options_resource
super(name, *args, &block) if defined?(super)
end
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
# Provider implementation for {Poise::Helpers::Inversion}.
# @see Poise::Helpers::Inversion
module Provider
include DefinedIn
# Compile all the different levels of inversion options together.
#
# @return [Hash]
# @example
# def action_run
# if options['depends']
# # ...
# end
# end
def options
@options ||= self.class.inversion_options(node, new_resource)
end
# @!classmethods
module ClassMethods
# @overload inversion_resource()
# Return the inversion resource name for this class.
# @return [Symbo, nill]
# @overload inversion_resource(val)
# Set the inversion resource name for this class. You can pass either
# a symbol in DSL format or a resource class that uses Poise. This
# name is used to determine which resources the inversion provider is
# a candidate for.
# @param val [Symbol, Class] Name to set.
# @return [Symbol, nil]
def inversion_resource(val=Poise::NOT_PASSED)
if val != Poise::NOT_PASSED
val = val.resource_name if val.is_a?(Class)
Chef::Log.debug("[#{self.name}] Setting inversion resource to #{val}")
@poise_inversion_resource = val.to_sym
end
if defined?(@poise_inversion_resource)
@poise_inversion_resource
else
Poise::Utils.ancestor_send(self, :inversion_resource, default: nil)
end
end
# @overload inversion_attribute()
# Return the inversion attribute name(s) for this class.
# @return [Array<String>, nil]
# @overload inversion_attribute(val)
# Set the inversion attribute name(s) for this class. This is
# used by {.resolve_inversion_attribute} to load configuration data
# from node attributes. To specify a nested attribute pass an array
# of strings corresponding to the keys.
# @param val [String, Array<String>] Attribute path.
# @return [Array<String>, nil]
def inversion_attribute(val=Poise::NOT_PASSED)
if val != Poise::NOT_PASSED
# Coerce to an array of strings.
val = Array(val).map {|name| name.to_s }
@poise_inversion_attribute = val
end
if defined?(@poise_inversion_attribute)
@poise_inversion_attribute
else
Poise::Utils.ancestor_send(self, :inversion_attribute, default: nil)
end
end
# Default attribute paths to check for inversion options. Based on
# the cookbook this class and its superclasses are defined in.
#
# @param node [Chef::Node] Node to load from.
# @return [Array<Array<String>>]
def default_inversion_attributes(node)
klass = self
tried = []
while klass.respond_to?(:poise_defined_in_cookbook)
cookbook = klass.poise_defined_in_cookbook(node.run_context)
if node[cookbook]
return [cookbook]
end
tried << cookbook
klass = klass.superclass
end
raise Poise::Error.new("Unable to find inversion attributes, tried: #{tried.join(', ')}")
end
# Resolve the node attribute used as the base for inversion options
# for this class. This can be set explicitly with {.inversion_attribute}
# or the default is to use the name of the cookbook the provider is
# defined in.
#
# @param node [Chef::Node] Node to load from.
# @return [Chef::Node::Attribute]
def resolve_inversion_attribute(node)
# Default to using just the name of the cookbook.
attribute_names = inversion_attribute || default_inversion_attributes(node)
return {} if attribute_names.empty?
attribute_names.inject(node) do |memo, key|
memo[key] || begin
raise Poise::Error.new("Attribute #{key} not set when expanding inversion attribute for #{self.name}: #{memo}")
end
end
end
# Compile all the different levels of inversion options together.
#
# @param node [Chef::Node] Node to load from.
# @param resource [Chef::Resource] Resource to load from.
# @return [Hash]
def inversion_options(node, resource)
Mash.new.tap do |opts|
attrs = resolve_inversion_attribute(node)
# Cast the run state to a Mash because string vs. symbol keys. I can
# at least promise poise_inversion will be a str so cut down on the
# amount of data to convert.
run_state = Mash.new(node.run_state.fetch('poise_inversion', {}).fetch(inversion_resource, {}))[resource.name] || {}
# Class-level defaults.
opts.update(default_inversion_options(node, resource))
# Resource options for all providers.
opts.update(resource.options) if resource.respond_to?(:options)
# Global provider from node attributes.
opts.update(provider: attrs['provider']) if attrs['provider']
# Attribute options for all providers.
opts.update(attrs['options']) if attrs['options']
# Resource options for this provider.
opts.update(resource.options(provides)) if resource.respond_to?(:options)
# Attribute options for this resource name.
opts.update(attrs[resource.name]) if attrs[resource.name]
# Options resource options for all providers.
opts.update(run_state['*']) if run_state['*']
# Options resource options for this provider.
opts.update(run_state[provides]) if run_state[provides]
# Vomitdebug output for tracking down weirdness.
Poise.debug("[#{resource}] Resolved inversion options: #{opts.inspect}")
end
end
# Default options data for this provider class.
#
# @param node [Chef::Node] Node to load from.
# @param resource [Chef::Resource] Resource to load from.
# @return [Hash]
def default_inversion_options(node, resource)
{}
end
# Resolve which provider name should be used for a resource.
#
# @param node [Chef::Node] Node to load from.
# @param resource [Chef::Resource] Resource to query.
# @return [String]
def resolve_inversion_provider(node, resource)
inversion_options(node, resource)['provider'] || 'auto'
end
# Override the normal #provides to set the inversion provider name
# instead of adding to the normal provider map.
#
# @overload provides()
# Return the inversion provider name for the class.
# @return [Symbol]
# @overload provides(name, opts={}, &block)
# Set the inversion provider name for the class.
# @param name [Symbol] Provider name.
# @param opts [Hash] NodeMap filter options.
# @param block [Proc] NodeMap filter proc.
# @return [Symbol]
def provides(name=nil, opts={}, &block)
if name
raise Poise::Error.new("Inversion resource name not set for #{self.name}") unless inversion_resource
@poise_inversion_provider = name
Chef::Log.debug("[#{self.name}] Setting inversion provider name to #{name}")
Poise::Helpers::Inversion.provider_map(inversion_resource).set(name.to_sym, self, opts, &block)
# Set the actual Chef-level provides name for DSL dispatch.
super(inversion_resource)
end
@poise_inversion_provider
end
# Override the default #provides? to check for our inverted providers.
#
# @api private
# @param node [Chef::Node] Node to use for attribute checks.
# @param resource [Chef::Resource] Resource instance to match.
# @return [Boolean]
def provides?(node, resource)
raise Poise::Error.new("Inversion resource name not set for #{self.name}") unless inversion_resource
resource_name_equivalents = {resource.resource_name => true}
# If subclass_providers! might be in play, check for those names too.
if resource.class.respond_to?(:subclass_resource_equivalents)
resource.class.subclass_resource_equivalents.each do |name|
resource_name_equivalents[name] = true
end
end
return false unless resource_name_equivalents[inversion_resource]
provider_name = resolve_inversion_provider(node, resource)
Poise.debug("[#{resource}] Checking provides? on #{self.name}. Got provider_name #{provider_name.inspect}")
provider_name == provides.to_s || ( provider_name == 'auto' && !resource.provider_no_auto.include?(provides.to_s) && provides_auto?(node, resource) )
end
# Subclass hook to provide auto-detection for providers.
#
# @param node [Chef::Node] Node to check against.
# @param resource [Chef::Resource] Resource to check against.
# @return [Boolean]
def provides_auto?(node, resource)
false
end
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
# The provider map for a given resource type.
#
# @param resource_type [Symbol] Resource type in DSL format.
# @return [Chef::NodeMap]
# @example
# Poise::Helpers::Inversion.provider_map(:my_resource)
def self.provider_map(resource_type)
@provider_maps ||= {}
@provider_maps[resource_type.to_sym] ||= Chef::NodeMap.new
end
# Find a specific provider class for a resource.
#
# @param resource_type [Symbol] Resource type in DSL format.
# @param node [Chef::Node] Node to use for the lookup.
# @param provider_type [Symbol] Provider type in DSL format.
# @return [Class]
# @example
# Poise::Helpers::Inversion.provider_for(:my_resource, node, :my_provider)
def self.provider_for(resource_type, node, provider_type)
provider_map(resource_type).get(node, provider_type.to_sym)
end
end
end
end

View File

@ -1,41 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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.
#
module Poise
module Helpers
module Inversion
# A mixin for inversion options providers.
#
# @api private
# @since 2.0.0
# @see Poise::Helper::Inversion
module OptionsProvider
# @api private
def self.included(klass)
klass.class_exec { include Poise }
end
# A blank run action.
#
# @return [void]
def action_run
# This space left intentionally blank.
end
end
end
end
end

View File

@ -1,101 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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/mash'
require 'poise/error'
module Poise
module Helpers
module Inversion
# A mixin for inversion options resources.
#
# @api private
# @since 2.0.0
# @see Poise::Helpers::Inversion
module OptionsResource
include Poise
# Method missing delegation to allow DSL-style options.
#
# @example
# my_app_options 'app' do
# key1 'value1'
# key2 'value2'
# end
def method_missing(method_sym, *args, &block)
super(method_sym, *args, &block)
rescue NoMethodError
# First time we've seen this key and using it as an rvalue, NOPE.GIF.
raise unless !args.empty? || block || _options[method_sym]
if !args.empty? || block
_options[method_sym] = block || args.first
end
_options[method_sym]
end
# Insert the options data in to the run state. This has to match the
# layout used in {Poise::Helpers::Inversion::Provider.inversion_options}.
#
# @api private
def after_created
raise Poise::Error.new("Inversion resource name not set for #{self.class.name}") unless self.class.inversion_resource
node.run_state['poise_inversion'] ||= {}
node.run_state['poise_inversion'][self.class.inversion_resource] ||= {}
node.run_state['poise_inversion'][self.class.inversion_resource][resource] ||= {}
node.run_state['poise_inversion'][self.class.inversion_resource][resource][for_provider] ||= {}
node.run_state['poise_inversion'][self.class.inversion_resource][resource][for_provider].update(_options)
end
module ClassMethods
# @overload inversion_resource()
# Return the inversion resource name for this class.
# @return [Symbol]
# @overload inversion_resource(val)
# Set the inversion resource name for this class. You can pass either
# a symbol in DSL format or a resource class that uses Poise. This
# name is used to determine which resources the inversion provider is
# a candidate for.
# @param val [Symbol, Class] Name to set.
# @return [Symbol]
def inversion_resource(val=nil)
if val
val = val.resource_name if val.is_a?(Class)
Chef::Log.debug("[#{self.name}] Setting inversion resource to #{val}")
@poise_inversion_resource = val.to_sym
end
@poise_inversion_resource || (superclass.respond_to?(:inversion_resource) ? superclass.inversion_resource : nil)
end
# @api private
def included(klass)
super
klass.extend(ClassMethods)
klass.class_exec do
actions(:run)
attribute(:resource, kind_of: String, name_attribute: true)
attribute(:for_provider, kind_of: [String, Symbol], default: '*')
attribute(:_options, kind_of: Hash, default: lazy { Mash.new })
end
end
end
extend ClassMethods
end
end
end
end

View File

@ -1,79 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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/version'
module Poise
module Helpers
# Resource mixin to allow lazyily-evaluated defaults in resource attributes.
# This is designed to be used with {LWRPPolyfill} or a similar #attributes
# method.
#
# @since 1.0.0
# @example
# class MyResource < Chef::Resource
# include Poise::Helpers::LWRPPolyfill
# include Poise::Helpers::LazyDefault
# attribute(:path, default: lazy { name + '_temp' })
# end
module LazyDefault
# Check if this version of Chef already supports lazy defaults. This is
# true for Chef 12.5+.
#
# @since 2.0.3
# @api private
# @return [Boolean]
def self.needs_polyfill?
@needs_polyfill ||= Gem::Requirement.new('< 12.5.pre').satisfied_by?(Gem::Version.new(Chef::VERSION))
end
# Override the default set_or_return to support lazy evaluation of the
# default value. This only actually matters when it is called from a class
# level context via #attributes.
def set_or_return(symbol, arg, validation)
if LazyDefault.needs_polyfill? && validation && validation[:default].is_a?(Chef::DelayedEvaluator)
validation = validation.dup
if (arg.nil? || arg == Poise::NOT_PASSED) && (!instance_variable_defined?(:"@#{symbol}") || instance_variable_get(:"@#{symbol}").nil?)
validation[:default] = instance_eval(&validation[:default])
else
# Clear the default.
validation.delete(:default)
end
end
super(symbol, arg, validation)
end
# @!classmethods
module ClassMethods
# Create a lazyily-evaluated block.
#
# @param block [Proc] Callable to return the default value.
# @return [Chef::DelayedEvaluator]
def lazy(&block)
Chef::DelayedEvaluator.new(&block)
end
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
end
end

View File

@ -1,163 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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/resource'
require 'poise/utils/resource_provider_mixin'
module Poise
module Helpers
# A resource and provider mixin to add back some compatability with Chef's
# LWRPBase classes.
#
# @since 1.0.0
module LWRPPolyfill
include Poise::Utils::ResourceProviderMixin
# Provide default_action and actions like LWRPBase but better equipped for subclassing.
module Resource
def initialize(*args)
super
# Try to not stomp on stuff if already set in a parent. Coerce @action
# to an array because this behavior may change in the future in Chef.
@action = self.class.default_action if Array(@action) == [:nothing]
(@allowed_actions << self.class.actions).flatten!.uniq!
end
module ClassMethods
# @overload default_action()
# Get the default action for this resource class. If no explicit
# default is set, the first action in the list will be used.
# @see #actions
# @return [Array<Symbol>]
# @overload default_action(name)
# Set the default action for this resource class. If this action is
# not already allowed, it will be added.
# @note It is idiomatic to use {#actions} instead, with the first
# action specified being the default.
# @param name [Symbol, Array<Symbol>] Name of the action(s).
# @return [Array<Symbol>]
# @example
# class MyApp < Chef::Resource
# include Poise
# default_action(:install)
# end
def default_action(name=nil)
if name
name = Array(name).flatten.map(&:to_sym)
@default_action = name
actions(*name)
end
if @default_action
@default_action
elsif respond_to?(:superclass) && superclass != Chef::Resource && superclass.respond_to?(:default_action) && superclass.default_action && Array(superclass.default_action) != %i{nothing}
superclass.default_action
elsif first_non_nothing = actions.find {|action| action != :nothing }
[first_non_nothing]
else
%i{nothing}
end
end
# @overload actions()
# Get all actions allowed for this resource class. This includes
# any actions allowed on parent classes.
# @return [Array<Symbol>]
# @overload actions(*names)
# Set actions as allowed for this resource class. These must
# correspond with action methods in the provider class(es).
# @param names [Array<Symbol>] One or more actions to set.
# @return [Array<Symbol>]
# @example
# class MyApp < Chef::Resource
# include Poise
# actions(:install, :uninstall)
# end
def actions(*names)
@actions ||= ( respond_to?(:superclass) && superclass.respond_to?(:actions) && superclass.actions.dup ) || ( respond_to?(:superclass) && superclass != Chef::Resource && superclass.respond_to?(:allowed_actions) && superclass.allowed_actions.dup ) || []
(@actions << names).tap {|actions| actions.flatten!; actions.uniq! }
end
# Create a resource property (née attribute) on this resource class.
# This follows the same usage as the helper of the same name in Chef
# LWRPs.
#
# @param name [Symbol] Name of the property.
# @param opts [Hash<Symbol, Object>] Validation options and flags.
# @return [void]
# @example
# class MyApp < Chef::Resource
# include Poise
# attribute(:path, name_attribute: true)
# attribute(:port, kind_of: Integer, default: 8080)
# end
def attribute(name, opts={})
# Freeze the default value. This is done upstream too in Chef 12.5+.
opts[:default].freeze if opts && opts[:default]
# Ruby 1.8 can go to hell.
define_method(name) do |arg=nil, &block|
arg = block if arg.nil? # Try to allow passing either.
set_or_return(name, arg, opts)
end
end
# For forward compat with Chef 12.5+.
alias_method :property, :attribute
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
# Helper to handle load_current_resource for direct subclasses of Provider
module Provider
module LoadCurrentResource
def load_current_resource
@current_resource = if new_resource
new_resource.class.new(new_resource.name, run_context)
else
# Better than nothing, subclass can overwrite anyway.
Chef::Resource.new(nil, run_context)
end
end
end
# @!classmethods
module ClassMethods
def included(klass)
super
klass.extend(ClassMethods)
# Mask Chef::Provider#load_current_resource because it throws NotImplementedError.
if klass.is_a?(Class) && klass.superclass == Chef::Provider
klass.send(:include, LoadCurrentResource)
end
# Reinstate the Chef DSL, removed in Chef 12.
klass.send(:include, Chef::DSL::Recipe)
end
end
extend ClassMethods
end
end
end
end

View File

@ -1,78 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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 'poise/helpers/subcontext_block'
require 'poise/subcontext/runner'
module Poise
module Helpers
# A provider mixin to provide #notifying_block, a scoped form of Chef's
# use_inline_resources.
#
# @since 1.0.0
# @example
# class MyProvider < Chef::Provider
# include Chef::Helpers::NotifyingBlock
#
# def action_run
# notifying_block do
# template '/etc/myapp.conf' do
# # ...
# end
# end
# end
# end
module NotifyingBlock
include Poise::Helpers::SubcontextBlock
private
# Create and converge a subcontext for the recipe DSL. This is similar to
# Chef's use_inline_resources but is scoped to a block. All DSL resources
# declared inside the block will be converged when the block returns, and
# the updated_by_last_action flag will be set if any of the inner
# resources are updated.
#
# @api public
# @param block [Proc] Block to run in the subcontext.
# @return [void]
# @example
# def action_run
# notifying_block do
# template '/etc/myapp.conf' do
# # ...
# end
# end
# end
def notifying_block(&block)
# Make sure to mark the resource as updated-by-last-action if
# any sub-run-context resources were updated (any actual
# actions taken against the system) during the
# sub-run-context convergence.
begin
subcontext = subcontext_block(&block)
# Converge the new context.
Poise::Subcontext::Runner.new(new_resource, subcontext).converge
ensure
new_resource.updated_by_last_action(
subcontext && subcontext.resource_collection.any?(&:updated?)
)
end
end
end
end
end

View File

@ -1,142 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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/mash'
require 'poise/error'
module Poise
module Helpers
# A resource mixin to add a new kind of attribute, an option collector.
# These attributes can act as mini-DSLs for things which would otherwise be
# key/value pairs.
#
# @since 1.0.0
# @example Defining an option collector
# class MyResource < Chef::Resource
# include Poise::Helpers::OptionCollector
# attribute(:my_options, option_collector: true)
# end
# @example Using an option collector
# my_resource 'name' do
# my_options do
# key1 'value1'
# key2 'value2'
# end
# end
module OptionCollector
# Instance context used to eval option blocks.
# @api private
class OptionEvalContext
attr_reader :_options
def initialize(parent, forced_keys)
@parent = parent
@forced_keys = forced_keys
@_options = {}
end
def method_missing(method_sym, *args, &block)
# Deal with forced keys.
if @forced_keys.include?(method_sym)
@_options[method_sym] = args.first || block if !args.empty? || block
return @_options[method_sym]
end
# Try the resource context.
@parent.send(method_sym, *args, &block)
rescue NameError
# Even though method= in the block will set a variable instead of
# calling method_missing, still try to cope in case of self.method=.
method_sym = method_sym.to_s.chomp('=').to_sym
if !args.empty? || block
@_options[method_sym] = args.first || block
elsif !@_options.include?(method_sym)
# We haven't seen this name before, re-raise the NameError.
raise
end
@_options[method_sym]
end
end
# @!classmethods
module ClassMethods
# Override the normal #attribute() method to support defining option
# collectors too.
def attribute(name, options={})
# If present but false-y, make sure it is removed anyway so it
# doesn't confuse ParamsValidate.
if options.delete(:option_collector)
option_collector_attribute(name, options)
else
super
end
end
# Define an option collector attribute. Normally used via {.attribute}.
#
# @param name [String, Symbol] Name of the attribute to define.
# @param default [Hash] Default value for the options.
# @param parser [Proc, Symbol] Optional parser method. If a symbol it is
# called as a method on self. Takes a non-hash value and returns a
# hash of its parsed representation.
# @param forced_keys [Array<Symbol>, Set<Symbol>] Method names that will be forced
# to be options rather than calls to the parent resource.
def option_collector_attribute(name, default: {}, parser: nil, forced_keys: Set.new)
raise Poise::Error.new("Parser must be a Proc or Symbol: #{parser.inspect}") if parser && !(parser.is_a?(Proc) || parser.is_a?(Symbol))
# Cast to a set at definition time.
forced_keys = Set.new(forced_keys) unless forced_keys.is_a?(Set)
# Unlike LWRPBase.attribute, I don't care about Ruby 1.8. Worlds tiniest violin.
define_method(name.to_sym) do |arg=nil, &block|
iv_sym = :"@#{name}"
value = instance_variable_get(iv_sym) || begin
default = instance_eval(&default) if default.is_a?(Chef::DelayedEvaluator) # Handle lazy{}
Mash.new(default) # Wrap in a mash because fuck str vs sym.
end
if arg
if !arg.is_a?(Hash) && parser
arg = case parser
when Proc
instance_exec(arg, &parser)
when Symbol
send(parser, arg)
end
end
raise Exceptions::ValidationFailed, "Option #{name} must be a Hash" if !arg.is_a?(Hash)
# Should this and the update below be a deep merge?
value.update(arg)
end
if block
ctx = OptionEvalContext.new(self, forced_keys)
ctx.instance_exec(&block)
value.update(ctx._options)
end
instance_variable_set(iv_sym, value)
value
end
end
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
end
end

View File

@ -1,72 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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.
#
module Poise
module Helpers
# A resource mixin to disable resource cloning.
#
# @since 2.2.0
# @example
# class MyResource < Chef::Resource
# include Poise::Helpers::ResourceCloning
# end
module ResourceCloning
# Override to disable resource cloning on Chef 12.0.
#
# @api private
def load_prior_resource(*args)
# Do nothing.
end
# Override to disable resource cloning on Chef 12.1+.
#
# @api private
def load_from(*args)
# Do nothing.
end
# Monkeypatch for Chef::ResourceBuilder to silence the warning if needed.
#
# @api private
module ResourceBuilderPatch
# @api private
def self.install!
begin
require 'chef/resource_builder'
Chef::ResourceBuilder.send(:prepend, ResourceBuilderPatch)
rescue LoadError
# For 12.0, this is already taken care of.
end
end
# @api private
def emit_cloned_resource_warning
super unless resource.is_a?(ResourceCloning)
end
# @api private
def emit_harmless_cloning_debug
super unless resource.is_a?(ResourceCloning)
end
end
# Install the patch.
ResourceBuilderPatch.install!
end
end
end

View File

@ -1,107 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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/convert_to_class_name'
module Poise
module Helpers
# A resource mixin to automatically set @resource_name.
#
# @since 1.0.0
# @example
# class MyResource < Chef::Resource
# include Poise::Helpers::ResourceName
# provides(:my_resource)
# end
module ResourceName
def initialize(*args)
super
# If provides() was explicitly set, unconditionally set @resource_name.
# This helps when subclassing core Chef resources which set it
# themselves in #initialize.
if self.class.resource_name(false)
@resource_name = self.class.resource_name
else
@resource_name ||= self.class.resource_name
end
end
# @!classmethods
module ClassMethods
# Set the DSL name for the the resource class.
#
# @param name [Symbol] Name of the resource.
# @return [void]
# @example
# class MyResource < Chef::Resource
# include Poise::Resource::ResourceName
# provides(:my_resource)
# end
def provides(name, *args, &block)
# Patch self.constantize so this can cope with anonymous classes.
# This does require that the anonymous class define self.name though.
if self.name && respond_to?(:constantize)
old_constantize = instance_method(:constantize)
define_singleton_method(:constantize) do |const_name|
( const_name == self.name ) ? self : old_constantize.bind(self).call(const_name)
end
end
# Store the name for later.
@provides_name ||= name
# Call the original if present. The defined? is for old Chef.
super(name, *args, &block) if defined?(super)
end
# Retreive the DSL name for the resource class. If not set explicitly
# via {provides} this will try to auto-detect based on the class name.
#
# @param auto [Boolean] Try to auto-detect based on class name.
# @return [Symbol]
def resource_name(auto=true)
# In 12.4+ we need to proxy through the super class for setting.
return super(auto) if defined?(super) && (auto.is_a?(Symbol) || auto.is_a?(String))
return @provides_name unless auto
@provides_name || if name
mode = if name.start_with?('Chef::Resource')
[name, 'Chef::Resource']
else
[name.split('::').last]
end
Chef::Mixin::ConvertToClassName.convert_to_snake_case(*mode).to_sym
elsif defined?(super)
# No name on 12.4+ probably means this is an LWRP, use super().
super()
end
end
# Used by Resource#to_text to find the human name for the resource.
#
# @api private
def dsl_name
resource_name.to_s
end
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
end
end

View File

@ -1,82 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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 'poise/error'
require 'poise/helpers/resource_name'
module Poise
module Helpers
# A resource mixin to help subclass existing resources.
#
# @since 2.3.0
module ResourceSubclass
include ResourceName
module ClassMethods
def subclass_providers!(superclass_resource_name=nil, resource_name: nil)
resource_name ||= self.resource_name
superclass_resource_name ||= if superclass.respond_to?(:resource_name)
superclass.resource_name
elsif superclass.respond_to?(:dsl_name)
superclass.dsl_name
else
raise Poise::Error.new("Unable to determine superclass resource name for #{superclass}. Please specify name manually via subclass_providers!('name').")
end.to_sym
# Deal with the node maps.
node_maps = {}
node_maps['handler map'] = Chef.provider_handler_map if defined?(Chef.provider_handler_map)
node_maps['priority map'] = Chef.provider_priority_map if defined?(Chef.provider_priority_map)
# Patch anything in the descendants tracker.
Chef::Provider.descendants.each do |provider|
node_maps["#{provider} node map"] = provider.node_map if defined?(provider.node_map)
end if defined?(Chef::Provider.descendants)
node_maps.each do |map_name, node_map|
map = node_map.respond_to?(:map, true) ? node_map.send(:map) : node_map.instance_variable_get(:@map)
if map.include?(superclass_resource_name)
Chef::Log.debug("[#{self}] Copying provider mapping in #{map_name} from #{superclass_resource_name} to #{resource_name}")
map[resource_name] = map[superclass_resource_name].dup
end
end
# Add any needed equivalent names.
if superclass.respond_to?(:subclass_resource_equivalents)
subclass_resource_equivalents.concat(superclass.subclass_resource_equivalents)
else
subclass_resource_equivalents << superclass_resource_name
end
subclass_resource_equivalents.uniq!
end
# An array of names for the resources this class is equivalent to for
# the purposes of provider resolution.
#
# @return [Array<Symbol>]
def subclass_resource_equivalents
@subclass_resource_names ||= [resource_name.to_sym]
end
# @api private
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
end
end

View File

@ -1,72 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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 'poise/subcontext/resource_collection'
module Poise
module Helpers
# A provider mixin to help with creating subcontexts. Mostly for internal
# use within Poise.
#
# @since 1.0.0
module SubcontextBlock
private
def subcontext_block(parent_context=nil, &block)
# Setup a subcontext.
parent_context ||= @run_context
sub_run_context = parent_context.dup
# Reset state for the subcontext. In 12.4+ this uses the built-in
# support, otherwise do it manually.
if defined?(sub_run_context.initialize_child_state)
sub_run_context.initialize_child_state
else
# Audits was added in 12.1 I think.
sub_run_context.audits = {} if defined?(sub_run_context.audits)
# Dup and clear to preserve the default behavior without copy-pasta.
sub_run_context.immediate_notification_collection = parent_context.immediate_notification_collection.dup.clear
sub_run_context.delayed_notification_collection = parent_context.delayed_notification_collection.dup.clear
end
# Create the subcollection.
sub_run_context.resource_collection = Poise::Subcontext::ResourceCollection.new(parent_context.resource_collection)
# Create an accessor for the parent run context.
sub_run_context.define_singleton_method(:parent_run_context) { parent_context }
# Declare sub-resources within the sub-run-context. Since they
# are declared here, they do not pollute the parent run-context.
begin
outer_run_context = @run_context
@run_context = sub_run_context
instance_eval(&block)
ensure
@run_context = outer_run_context
end
# Return the inner context to do other things with
sub_run_context
end
def global_resource_collection
collection = @run_context.resource_collection
while collection.respond_to?(:parent) && collection.parent
collection = collection.parent
end
collection
end
end
end
end

View File

@ -1,29 +0,0 @@
#
# Copyright 2015, Noah Kantrowitz
#
# 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.
#
module Poise
module Helpers
# Mixins and helpers for managing subresources, resources with a
# parent/child relationship.
#
# @since 2.0.0
module Subresources
autoload :Child, 'poise/helpers/subresources/child'
autoload :Container, 'poise/helpers/subresources/container'
end
end
end

View File

@ -1,276 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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/resource'
require 'poise/error'
require 'poise/helpers/subresources/default_containers'
module Poise
module Helpers
module Subresources
# A resource mixin for child subresources.
#
# @since 1.0.0
module Child
# Little class used to fix up the display of subresources in #to_text.
# Without this you get the full parent resource shown for @parent et al.
# @api private
class ParentRef
attr_accessor :resource
def initialize(resource)
@resource = resource
end
def inspect
to_text
end
def to_text
if @resource.nil?
'nil'
else
@resource.to_s
end
end
end
# @overload parent()
# Get the parent resource for this child. This may be nil if the
# resource is set to parent_optional = true.
# @return [Chef::Resource, nil]
# @overload parent(val)
# Set the parent resource. The parent can be set as resource
# object, a string (either a bare resource name or a type[name]
# string), or a type:name hash.
# @param val [String, Hash, Chef::Resource] Parent resource to set.
# @return [Chef::Resource, nil]
def parent(*args)
# Lie about this method if the parent type is true.
if self.class.parent_type == true
raise NoMethodError.new("undefined method `parent' for #{self}")
end
_parent(:parent, self.class.parent_type, self.class.parent_optional, self.class.parent_auto, self.class.parent_default, *args)
end
# Register ourself with parents in case this is not a nested resource.
#
# @api private
def after_created
super
self.class.parent_attributes.each_key do |name|
parent = self.send(name)
parent.register_subresource(self) if parent && parent.respond_to?(:register_subresource)
end
end
private
# Generic form of the parent getter/setter.
#
# @since 2.0.0
# @see #parent
def _parent(name, parent_type, parent_optional, parent_auto, parent_default, *args)
# Allow using a DSL symbol as the parent type.
if parent_type.is_a?(Symbol)
parent_type = Chef::Resource.resource_for_node(parent_type, node)
end
# Grab the ivar for local use.
parent_ref = instance_variable_get(:"@#{name}")
if !args.empty?
val = args.first
if val.nil?
# Unsetting the parent.
parent = parent_ref = nil
else
if val.is_a?(String) && !val.include?('[')
raise Poise::Error.new("Cannot use a string #{name} without defining a parent type") if parent_type == Chef::Resource
# Try to find the most recent instance of parent_type with a
# matching name. This takes subclassing parent_type into account.
found_val = nil
iterator = run_context.resource_collection.respond_to?(:recursive_each) ? :recursive_each : :each
# This will find the last matching value due to overwriting
# found_val as it goes. Will be the nearest match.
run_context.resource_collection.public_send(iterator) do |res|
found_val = res if res.is_a?(parent_type) && res.name == val
end
# If found_val is nil, fall back to using lookup even though
# it won't work with subclassing, better than nothing?
val = found_val || "#{parent_type.resource_name}[#{val}]"
end
if val.is_a?(String) || val.is_a?(Hash)
parent = @run_context.resource_collection.find(val)
else
parent = val
end
if !parent.is_a?(parent_type)
raise Poise::Error.new("Parent resource is not an instance of #{parent_type.name}: #{val.inspect}")
end
parent_ref = ParentRef.new(parent)
end
elsif !parent_ref || !parent_ref.resource
if parent_default
parent = if parent_default.is_a?(Chef::DelayedEvaluator)
instance_eval(&parent_default)
else
parent_default
end
end
# The @parent_ref means we won't run this if we previously set
# ParentRef.new(nil). This means auto-lookup only happens during
# after_created.
if !parent && !parent_ref && parent_auto
# Automatic sibling lookup for sequential composition.
# Find the last instance of the parent class as the default parent.
# This is super flaky and should only be a last resort.
parent = Poise::Helpers::Subresources::DefaultContainers.find(parent_type, run_context, self_resource: self)
end
# Can't find a valid parent, if it wasn't optional raise an error.
raise Poise::Error.new("No #{name} found for #{self}") unless parent || parent_optional
parent_ref = ParentRef.new(parent)
else
parent = parent_ref.resource
end
raise Poise::Error.new("Cannot set the #{name} of #{self} to itself") if parent.equal?(self)
# Store the ivar back.
instance_variable_set(:"@#{name}", parent_ref)
# Return the actual resource.
parent
end
module ClassMethods
# @overload parent_type()
# Get the class of the default parent link on this resource.
# @return [Class, Symbol]
# @overload parent_type(type)
# Set the class of the default parent link on this resource.
# @param type [Class, Symbol] Class to set.
# @return [Class, Symbol]
def parent_type(type=nil)
if type
raise Poise::Error.new("Parent type must be a class, symbol, or true, got #{type.inspect}") unless type.is_a?(Class) || type.is_a?(Symbol) || type == true
# Setting to true shouldn't actually do anything if a type was already set.
@parent_type = type unless type == true && !@parent_type.nil?
end
# First ancestor_send looks for a non-true && non-default value,
# second one is to check for default vs true if no real value is found.
@parent_type || Poise::Utils.ancestor_send(self, :parent_type, ignore: [Chef::Resource, true]) || Poise::Utils.ancestor_send(self, :parent_type, default: Chef::Resource)
end
# @overload parent_optional()
# Get the optional mode for the default parent link on this resource.
# @return [Boolean]
# @overload parent_optional(val)
# Set the optional mode for the default parent link on this resource.
# @param val [Boolean] Mode to set.
# @return [Boolean]
def parent_optional(val=nil)
unless val.nil?
@parent_optional = val
end
if @parent_optional.nil?
Poise::Utils.ancestor_send(self, :parent_optional, default: false)
else
@parent_optional
end
end
# @overload parent_auto()
# Get the auto-detect mode for the default parent link on this resource.
# @return [Boolean]
# @overload parent_auto(val)
# Set the auto-detect mode for the default parent link on this resource.
# @param val [Boolean] Mode to set.
# @return [Boolean]
def parent_auto(val=nil)
unless val.nil?
@parent_auto = val
end
if @parent_auto.nil?
Poise::Utils.ancestor_send(self, :parent_auto, default: true)
else
@parent_auto
end
end
# @overload parent_default()
# Get the default value for the default parent link on this resource.
# @since 2.3.0
# @return [Object, Chef::DelayedEvaluator]
# @overload parent_default(val)
# Set the default value for the default parent link on this resource.
# @since 2.3.0
# @param val [Object, Chef::DelayedEvaluator] Default value to set.
# @return [Object, Chef::DelayedEvaluator]
def parent_default(*args)
unless args.empty?
@parent_default = args.first
end
if defined?(@parent_default)
@parent_default
else
Poise::Utils.ancestor_send(self, :parent_default)
end
end
# Create a new kind of parent link.
#
# @since 2.0.0
# @param name [Symbol] Name of the relationship. This becomes a method
# name on the resource instance.
# @param type [Class] Class of the parent.
# @param optional [Boolean] If the parent is optional.
# @param auto [Boolean] If the parent is auto-detected.
# @return [void]
def parent_attribute(name, type: Chef::Resource, optional: false, auto: true, default: nil)
name = :"parent_#{name}"
(@parent_attributes ||= {})[name] = type
define_method(name) do |*args|
_parent(name, type, optional, auto, default, *args)
end
end
# Return the name of all parent relationships on this class.
#
# @since 2.0.0
# @return [Hash<Symbol, Class>]
def parent_attributes
{}.tap do |attrs|
# Grab superclass's attributes if possible.
attrs.update(Poise::Utils.ancestor_send(self, :parent_attributes, default: {}))
# Local default parent.
attrs[:parent] = parent_type
# Extra locally defined parents.
attrs.update(@parent_attributes) if @parent_attributes
# Remove anything with the type set to true.
attrs.reject! {|name, type| type == true }
end
end
# @api private
def included(klass)
super
klass.extend(ClassMethods)
end
end
extend ClassMethods
end
end
end
end

View File

@ -1,229 +0,0 @@
#
# Copyright 2013-2015, Noah Kantrowitz
#
# 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/dsl/recipe'
require 'poise/helpers/subcontext_block'
require 'poise/helpers/subresources/default_containers'
module Poise
module Helpers
module Subresources
# A resource mixin for subresource containers.
#
# @since 1.0.0
module Container
# A resource collection that has much more condensed text output. This
# is used to show the value of @subresources during Chef's error formatting.
# @api private
class NoPrintingResourceCollection < Chef::ResourceCollection
def inspect
to_text
end
def to_text
"[#{all_resources.map(&:to_s).join(', ')}]"
end
end
include SubcontextBlock
include Chef::DSL::Recipe
attr_reader :subresources
attr_reader :subcontexts
def initialize(*args)
super
@subresources = NoPrintingResourceCollection.new
@subcontexts = []
end
def after_created
super
# Register as a default container if needed.
Poise::Helpers::Subresources::DefaultContainers.register!(self, run_context) if self.class.container_default
# Add all internal subresources to the resource collection.
unless @subresources.empty?
Chef::Log.debug("[#{self}] Adding subresources to collection:")
# Because after_create is run before adding the container to the resource collection
# we need to jump through some hoops to get it swapped into place.
self_ = self
order_fixer = Chef::Resource::RubyBlock.new('subresource_order_fixer', @run_context)
# respond_to? is for <= 12.0.2, remove some day when I stop caring.
order_fixer.declared_type = 'ruby_block' if order_fixer.respond_to?(:declared_type=)
order_fixer.block do
Chef::Log.debug("[#{self_}] Running order fixer")
collection = self_.run_context.resource_collection
# Delete the current container resource from its current position.
collection.all_resources.delete(self_)
# Replace the order fixer with the container so it runs before all
# subresources.
collection.all_resources[collection.iterator.position] = self_
# Hack for Chef 11 to reset the resources_by_name position too.
# @todo Remove this when I drop support for Chef 11.
if resources_by_name = collection.instance_variable_get(:@resources_by_name)
resources_by_name[self_.to_s] = collection.iterator.position
end
# Step back so we re-run the "current" resource, which is now the
# container.
collection.iterator.skip_back
Chef::Log.debug("Collection: #{@run_context.resource_collection.map(&:to_s).join(', ')}")
end
@run_context.resource_collection.insert(order_fixer)
@subcontexts.each do |ctx|
# Copy all resources to the outer context.
ctx.resource_collection.each do |r|
Chef::Log.debug(" * #{r}")
# Fix the subresource to use the outer run context.
r.run_context = @run_context
@run_context.resource_collection.insert(r)
end
# Copy all notifications to the outer context.
%w{immediate delayed}.each do |notification_type|
ctx.send(:"#{notification_type}_notification_collection").each do |key, notifications|
notifications.each do |notification|
parent_notifications = @run_context.send(:"#{notification_type}_notification_collection")[key]
unless parent_notifications.any? { |existing_notification| existing_notification.duplicates?(notification) }
parent_notifications << notification
end
end
end
end
end
Chef::Log.debug("Collection: #{@run_context.resource_collection.map(&:to_s).join(', ')}")
end
end
def declare_resource(type, name, created_at=nil, &block)
Chef::Log.debug("[#{self}] Creating subresource from #{type}(#{name})")
self_ = self
# Used to break block context, non-local return from subcontext_block.
resource = []
# Grab the caller so we can make the subresource look like it comes from
# correct place.
created_at ||= caller[0]
# Run this inside a subcontext to avoid adding to the current resource collection.
# It will end up added later, indirected via @subresources to ensure ordering.
@subcontexts << subcontext_block do
namespace = if self.class.container_namespace == true
# If the value is true, use the name of the container resource.
self.name
elsif self.class.container_namespace.is_a?(Proc)
instance_eval(&self.class.container_namespace)
else
self.class.container_namespace
end
sub_name = if name && !name.empty?
if namespace
"#{namespace}::#{name}"
else
name
end
else
# If you pass in nil or '', you just get the namespace or parent name.
namespace || self.name
end
resource << super(type, sub_name, created_at) do
# Apply the correct parent before anything else so it is available
# in after_created for the subresource. It might raise
# NoMethodError is there isn't a real parent.
begin
parent(self_) if respond_to?(:parent)
rescue NoMethodError
# This space left intentionally blank.
end
# Run the resource block.
instance_exec(&block) if block
end
end
# Try and add to subresources. For normal subresources this is handled
# in the after_created.
register_subresource(resource.first) if resource.first
# Return whatever we have
resource.first
end
# Register a resource as part of this container. Returns true if the
# resource was added to the collection and false if it was already
# known.
#
# @note Return value added in 2.4.0.
# @return [Boolean]
def register_subresource(resource)
subresources.lookup(resource)
false
rescue Chef::Exceptions::ResourceNotFound
Chef::Log.debug("[#{self}] Adding #{resource} to subresources")
subresources.insert(resource)
true
end
private
# Thanks Array.flatten, big help you are. Specifically the
# method_missing in the recipe DSL will make a flatten on an array of
# resources fail, so make this safe.
def to_ary
nil
end
# @!classmethods
module ClassMethods
def container_namespace(val=nil)
@container_namespace = val unless val.nil?
if @container_namespace.nil?
# Not set here, look at the superclass or true by default for backwards compat.
Poise::Utils.ancestor_send(self, :container_namespace, default: true)
else
@container_namespace
end
end
# @overload container_default()
# Get the default mode for this resource. If false, this resource
# class will not be used for default container lookups. Defaults to
# true.
# @since 2.3.0
# @return [Boolean]
# @overload container_default(val)
# Set the default mode for this resource.
# @since 2.3.0
# @param val [Boolean] Default mode to set.
# @return [Boolean]
def container_default(val=nil)
@container_default = val unless val.nil?
if @container_default.nil?
# Not set here, look at the superclass or true by default for backwards compat.
Poise::Utils.ancestor_send(self, :container_default, default: true)
else
@container_default
end
end
def included(klass)
super
klass.extend(ClassMethods)
klass.const_get(:HIDDEN_IVARS) << :@subcontexts
klass.const_get(:FORBIDDEN_IVARS) << :@subcontexts
end
end
extend ClassMethods
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More