Initial Chef repository

This commit is contained in:
Greg Karékinian
2015-07-21 19:45:23 +02:00
parent 7e5401fc71
commit ee4079fa85
1151 changed files with 185163 additions and 0 deletions

View File

@@ -0,0 +1,207 @@
Database cookbook README
========================
v4.0.6 (2015-04-29)
-------------------
- #126 - Use sql_query property instead of sql in the mysql provider for :query action
v4.0.5 (2015-04-08)
-------------------
- #137/#138 - Removing log message containing password information
v4.0.4 (2015-04-07)
-------------------
- Using unescaped db name in field value
v4.0.3 (2015-02-22)
-------------------
- Unbreak postgresql_database_resource on older versions of PostgreSQL
v4.0.2 (2015-02-09)
-------------------
- Removing leftover mysql recipe that installs the mysql2_chef_gem.
v4.0.1 (2015-02-05)
-------------------
- Fixing merge conflicts with master on 4.0.0 attempted release
v4.0.0 (2015-02-05)
-------------------
- Decoupled mysql2_chef_gem cookbook.
Users must now install it themselves before utilizing mysql_database
or mysql_database_user resources.
- Fixing various MilClass errors in mysql providers
- Restoring missing :query action for mysql
- Restoring grant_option support for mysql
- Adding revoke action for mysql
v3.1.0 (2015-01-30)
-------------------
- Add support for postgresql_database_user privileges
- Add postgresql_database_test cookbook to test/fixtures
v3.0.3 (2015-01-20)
-------------------
- Bugfix: bugfix: lack of node['mysql']['version'] causing NilClass error
v3.0.2 (2015-01-16)
-------------------
- Fix bug to allow grants on databases with special characters
v3.0.1 (2015-01-16)
-------------------
- Enabling ssl for provider_mysql_database_user
v3.0.0 (2015-01-15)
-------------------
- Removing out of scope recipes
- porting to mysql2_chef_gem
- adding test-kitchen suites for mysql
v2.3.1 (2014-12-13)
-------------------
- Locking mysql and mysql-chef_gem dependencies down in metadata.rb
v2.3.0 (2014-08-13)
-------------------
- [#62] Allow requiring SSL
v2.2.0 (2014-05-07)
-------------------
- [COOK-4626] Add windows users for SQL Server
- [COOK-4627] Assigning sys_roles in SQL Server
v2.1.10 (2014-05-07)
--------------------
- [COOK-4614] - Update README to reflect gem installation via mysql-chef_gem
v2.1.8 (2014-04-23)
-------------------
- [COOK-4583] - Add ChefSpec matchers
v2.1.6 (2014-04-10)
-------------------
- [COOK-4538] Bump supported Chef version
v2.1.4 (2014-04-09)
-------------------
[COOK-4529] Query action ignores MySQL errors
v2.1.2 (2014-04-01)
-------------------
- Depending on mysql-chef_gem cookbook
v2.1.0 (2014-03-31)
-------------------
- Updating mysql cookbook dependency
- Enforcing rubocops
v2.0.0 (2014-02-25)
-------------------
[COOK-3441] database_user password argument should not be required
v1.6.0
------
### New Feature
- **[COOK-4009](https://tickets.chef.io/browse/COOK-4009)** - Add PostgreSQL SCHEMA management capability
### Improvement
- **[COOK-3862](https://tickets.chef.io/browse/COOK-3862)** - Improve database cookbook documentation
v1.5.2
------
### Improvement
- **[COOK-3716](https://tickets.chef.io/browse/COOK-3716)** - Add ALTER SQL Server user roles
v1.5.0
------
### Improvement
- **[COOK-3546](https://tickets.chef.io/browse/COOK-3546)** - Add connection parameters `:socket`
- **[COOK-1709](https://tickets.chef.io/browse/COOK-1709)** - Add 'grant_option' parameter
v1.4.0
-------
### Bug
- [COOK-2074]: Regex in exists? check in `sql_server_database` resource should match for start and end of line
- [COOK-2561]: `mysql_database_user` can't set global grants
### Improvement
- [COOK-2075]: Support the collation attribute in the `database_sql_server` provider
v1.3.12
-------
- [COOK-850] - `postgresql_database_user` doesn't have example
v1.3.10
-------
- [COOK-2117] - undefined variable `grant_statement` in mysql user provider
v1.3.8
------
- [COOK-1896] - Escape command
- [COOK-2047] - Chef::Provider::Database::MysqlUser action :grant improperly quotes `username`@`host` string
- [COOK-2060] - Mysql::Error: Table '*.*' doesn't exist when privileges include SELECT and database/table attributes are nil
- [COOK-2062] - Remove backticks from database name when using wildcard
v1.3.6
------
- [COOK-1688] - fix typo in readme and add amazon linux to supported platforms
v1.3.4
------
- [COOK-1561] - depend on mysql 1.3.0+ explicitly
- depend on postgresql 1.0.0 explicitly
v1.3.2
------
- Update the version for release (oops)
v1.3.0
------
- [COOK-932] - Add mysql recipe to conveniently include mysql::ruby
- [COOK-1228] - database resource should be able to execute scripts on disk
- [COOK-1291] - make the snapshot retention policy less confusing
- [COOK-1401] - Allow to specify the collation of new databases
- [COOK-1534] - Add postgresql recipe to conveniently include postgresql::ruby
v1.2.0
------
- [COOK-970] - workaround for disk [re]naming on ubuntu 11.04+
- [COOK-1085] - check RUBY_VERSION and act accordingly for role
- [COOK-749] - localhost should be a string in snapshot recipe
v1.1.4
------
- [COOK-1062] - Databases: Postgres exists should close connection
v1.1.2
------
- [COOK-975] - Change arg='DEFAULT' to arg=nil, :default => 'DEFAULT'
- [COOK-964] - Add parentheses around connection hash in example
v1.1.0
------
- [COOK-716] - providers for PostgreSQL
v1.0.0
------
- [COOK-683] - added `database` and `database_user` resources
- [COOK-684] - MySQL providers
- [COOK-685] - SQL Server providers
- refactored - `database::master` and `database::snapshot` recipes to leverage new resources
v0.99.1
-------
- Use Chef 0.10's `node.chef_environment` instead of `node['app_environment']`.

View File

@@ -0,0 +1,647 @@
Database Cookbook
=================
The main highlight of this cookbook is the `database` and
`database_user` resources for managing databases and database users in
a RDBMS. Providers for MySQL, PostgreSQL and SQL Server are also
provided, see usage documentation below.
Requirements
------------
Chef version 0.11+
### Platforms
- Debian, Ubuntu
- Red Hat, CentOS, Scientific, Fedora, Amazon
### Cookbooks
The following Chef Software cookbooks are dependencies:
* postgresql
Resources/Providers
-------------------
These resources aim to expose an abstraction layer for interacting
with different RDBMS in a general way. Currently the cookbook ships
with providers for MySQL, PostgreSQL and SQL Server. Please see
specific usage in the __Example__ sections below. The providers use
specific Ruby gems installed under Chef's Ruby environment to execute
commands and carry out actions. These gems will need to be installed
before the providers can operate correctly. Specific notes for each
RDBS flavor:
- MySQL: leverages the `mysql2` gem, which can be installed with the
`mysql2_chef_gem` resource prior to use (available on the
Supermarket). You must depend on the `mysql2_chef_gem` cookbook,
then use a `mysql2_chef_gem` resource to install it. The resource
allows the user to select MySQL client library versions, as well as
optionally select MariaDB libraries.
- PostgreSQL: leverages the `pg` gem which is installed as part of the
`postgresql::ruby` recipe. You must declare `include_recipe
"database::postgresql"` to include this.
- SQL Server: leverages the `tiny_tds` gem which is installed as part
of the `sql_server::client` recipe.
### database
Manage databases in a RDBMS. Use the proper shortcut resource
depending on your RDBMS: `mysql_database`, `postgresql_database` or
`sql_server_database`.
#### Actions
- :create: create a named database
- :drop: drop a named database
- :query: execute an arbitrary query against a named database
#### Attribute Parameters
- database_name: name attribute. Name of the database to interact with
- connection: hash of connection info. valid keys include `:host`,
`:port`, `:username`, and `:password` (only for MySQL DB*)
- sql: string of sql or a block that executes to a string of sql,
which will be executed against the database. used by `:query` action
only
\* The database cookbook uses the `mysql2` gem.
> "The value of host may be either a host name or an IP address. If
host is NULL or the string "127.0.0.1", a connection to the local
host is assumed. For Windows, the client connects using a
shared-memory connection, if the server has shared-memory
connections enabled. Otherwise, TCP/IP is used. For a host value of
"." on Windows, the client connects using a named pipe, if the
server has named-pipe connections enabled. If named-pipe connections
are not enabled, an error occurs."
If you specify a `:socket` key and are using the mysql_service
resource to set up the MySQL service, you'll need to specify the path
in the form `/var/run/mysql-<instance name>/mysqld.sock`.
#### Providers
- `Chef::Provider::Database::Mysql`: shortcut resource `mysql_database`
- `Chef::Provider::Database::Postgresql`: shortcut resource `postgresql_database`
- `Chef::Provider::Database::SqlServer`: shortcut resource `sql_server_database`
#### Examples
```ruby
# Create a mysql database
mysql_database 'wordpress-cust01' do
connection(
:host => '127.0.0.1',
:username => 'root',
:password => node['wordpress-cust01']['mysql']['initial_root_password']
)
action :create
end
```
```ruby
# Create a mysql database on a named mysql instance
mysql_database 'oracle_rools' do
connection(
:host => '127.0.0.1',
:username => 'root',
:socket => "/var/run/mysql-#{instance-name}/mysqld.sock"
:password => node['mysql']['server_root_password']
)
action :create
end
```
```ruby
# Create a sql server database
sql_server_database 'mr_softie' do
connection(
:host => '127.0.0.1',
:port => node['sql_server']['port'],
:username => 'sa',
:password => node['sql_server']['server_sa_password']
)
action :create
end
```
```ruby
# create a postgresql database
postgresql_database 'mr_softie' do
connection(
:host => '127.0.0.1',
:port => 5432,
:username => 'postgres',
:password => node['postgresql']['password']['postgres']
)
action :create
end
```
```ruby
# create a postgresql database with additional parameters
postgresql_database 'mr_softie' do
connection(
:host => '127.0.0.1',
:port => 5432,
:username => 'postgres',
:password => node['postgresql']['password']['postgres']
)
template 'DEFAULT'
encoding 'DEFAULT'
tablespace 'DEFAULT'
connection_limit '-1'
owner 'postgres'
action :create
end
```
```ruby
# Externalize conection info in a ruby hash
mysql_connection_info = {
:host => '127.0.0.1',
:username => 'root',
:password => node['mysql']['server_root_password']
}
sql_server_connection_info = {
:host => '127.0.0.1',
:port => node['sql_server']['port'],
:username => 'sa',
:password => node['sql_server']['server_sa_password']
}
postgresql_connection_info = {
:host => '127.0.0.1',
:port => node['postgresql']['config']['port'],
:username => 'postgres',
:password => node['postgresql']['password']['postgres']
}
# Same create commands, connection info as an external hash
mysql_database 'foo' do
connection mysql_connection_info
action :create
end
sql_server_database 'foo' do
connection sql_server_connection_info
action :create
end
postgresql_database 'foo' do
connection postgresql_connection_info
action :create
end
# Create database, set provider in resource parameter
database 'bar' do
connection mysql_connection_info
provider Chef::Provider::Database::Mysql
action :create
end
database 'bar' do
connection sql_server_connection_info
provider Chef::Provider::Database::SqlServer
action :create
end
database 'bar' do
connection postgresql_connection_info
provider Chef::Provider::Database::Postgresql
action :create
end
# Drop a database
mysql_database 'baz' do
connection mysql_connection_info
action :drop
end
# Query a database
mysql_database 'flush the privileges' do
connection mysql_connection_info
sql 'flush privileges'
action :query
end
# Query a database from a sql script on disk
mysql_database 'run script' do
connection mysql_connection_info
sql { ::File.open('/path/to/sql_script.sql').read }
action :query
end
# Vacuum a postgres database
postgresql_database 'vacuum databases' do
connection postgresql_connection_info
database_name 'template1'
sql 'VACUUM FULL VERBOSE ANALYZE'
action :query
end
```
### database_user
Manage users and user privileges in a RDBMS. Use the proper shortcut resource depending on your RDBMS: `mysql_database_user`, `postgresql_database_user`, or `sql_server_database_user`.
#### Actions
- :create: create a user
- :drop: drop a user
- :grant: manipulate user privileges on database objects
#### Attribute Parameters
- username: name attribute. Name of the database user
- password: password for the user account
- database_name: Name of the database to interact with
- connection: hash of connection info. valid keys include :host,
:port, :username, :password
- privileges: array of database privileges to grant user. used by the
:grant action. default is :all
- host: host where user connections are allowed from. used by MySQL
provider only. default is '127.0.0.1'
- table: table to grant privileges on. used by :grant action and MySQL
provider only. default is '*' (all tables)
- require_ssl: true or false to force SSL connections to be used for user
### Providers
- **Chef::Provider::Database::MysqlUser**: shortcut resource
`mysql_database_user`
- **Chef::Provider::Database::PostgresqlUser**: shortcut
resource `postgresql_database_user`
- **Chef::Provider::Database::SqlServerUser**: shortcut resource
`sql_server_database_user`
### Examples
# create connection info as an external ruby hash
mysql_connection_info = {:host => "127.0.0.1",
:username => 'root',
:password => node['mysql']['server_root_password']}
postgresql_connection_info = {:host => "127.0.0.1",
:port => node['postgresql']['config']['port'],
:username => 'postgres',
:password => node['postgresql']['password']['postgres']}
sql_server_connection_info = {:host => "127.0.0.1",
:port => node['sql_server']['port'],
:username => 'sa',
:password => node['sql_server']['server_sa_password']}
# create a mysql user but grant no privileges
mysql_database_user 'disenfranchised' do
connection mysql_connection_info
password 'super_secret'
action :create
end
# do the same but pass the provider to the database resource
database_user 'disenfranchised' do
connection mysql_connection_info
password 'super_secret'
provider Chef::Provider::Database::MysqlUser
action :create
end
# create a postgresql user but grant no privileges
postgresql_database_user 'disenfranchised' do
connection postgresql_connection_info
password 'super_secret'
action :create
end
# do the same but pass the provider to the database resource
database_user 'disenfranchised' do
connection postgresql_connection_info
password 'super_secret'
provider Chef::Provider::Database::PostgresqlUser
action :create
end
# create a sql server user but grant no privileges
sql_server_database_user 'disenfranchised' do
connection sql_server_connection_info
password 'super_secret'
action :create
end
# drop a mysql user
mysql_database_user "foo_user" do
connection mysql_connection_info
action :drop
end
# bulk drop sql server users
%w{ disenfranchised foo_user }.each do |user|
sql_server_database_user user do
connection sql_server_connection_info
action :drop
end
end
# grant select,update,insert privileges to all tables in foo db from all hosts, requiring connections over SSL
mysql_database_user 'foo_user' do
connection mysql_connection_info
password 'super_secret'
database_name 'foo'
host '%'
privileges [:select,:update,:insert]
require_ssl true
action :grant
end
# grant all privileges on all databases/tables from 127.0.0.1
mysql_database_user 'super_user' do
connection mysql_connection_info
password 'super_secret'
action :grant
end
# grant all privileges on all tables in foo db
postgresql_database_user 'foo_user' do
connection postgresql_connection_info
database_name 'foo'
privileges [:all]
action :grant
end
# grant select,update,insert privileges to all tables in foo db
sql_server_database_user 'foo_user' do
connection sql_server_connection_info
password 'super_secret'
database_name 'foo'
privileges [:select,:update,:insert]
action :grant
end
#### Providers
- `Chef::Provider::Database::MysqlUser`: shortcut resource `mysql_database_user`
- `Chef::Provider::Database::PostgresqlUser`: shortcut resource `postgresql_database_user`
- `Chef::Provider::Database::SqlServerUser`: shortcut resource`sql_server_database_user`
#### Examples
```ruby
# create connection info as an external ruby hash
mysql_connection_info = {
:host => '127.0.0.1',
:username => 'root',
:password => node['mysql']['server_root_password']
}
postgresql_connection_info = {
:host => '127.0.0.1',
:port => node['postgresql']['config']['port'],
:username => 'postgres',
:password => node['postgresql']['password']['postgres']
}
sql_server_connection_info = {
:host => '127.0.0.1',
:port => node['sql_server']['port'],
:username => 'sa',
:password => node['sql_server']['server_sa_password']
}
# Create a mysql user but grant no privileges
mysql_database_user 'disenfranchised' do
connection mysql_connection_info
password 'super_secret'
action :create
end
# Do the same but pass the provider to the database resource
database_user 'disenfranchised' do
connection mysql_connection_info
password 'super_secret'
provider Chef::Provider::Database::MysqlUser
action :create
end
# Create a postgresql user but grant no privileges
postgresql_database_user 'disenfranchised' do
connection postgresql_connection_info
password 'super_secret'
action :create
end
# Do the same but pass the provider to the database resource
database_user 'disenfranchised' do
connection postgresql_connection_info
password 'super_secret'
provider Chef::Provider::Database::PostgresqlUser
action :create
end
# Create a sql server user but grant no privileges
sql_server_database_user 'disenfranchised' do
connection sql_server_connection_info
password 'super_secret'
action :create
end
# Drop a mysql user
mysql_database_user 'foo_user' do
connection mysql_connection_info
action :drop
end
# Bulk drop sql server users
%w(disenfranchised foo_user).each do |user|
sql_server_database_user user do
connection sql_server_connection_info
action :drop
end
end
# Grant SELECT, UPDATE, and INSERT privileges to all tables in foo db from all hosts
mysql_database_user 'foo_user' do
connection mysql_connection_info
password 'super_secret'
database_name 'foo'
host '%'
privileges [:select,:update,:insert]
action :grant
end
# Grant all privileges on all databases/tables from 127.0.0.1
mysql_database_user 'super_user' do
connection mysql_connection_info
password 'super_secret'
action :grant
end
# Grant all privileges on all tables in foo db
postgresql_database_user 'foo_user' do
connection postgresql_connection_info
database_name 'foo'
privileges [:all]
action :grant
end
# grant select,update,insert privileges to all tables in foo db
sql_server_database_user 'foo_user' do
connection sql_server_connection_info
password 'super_secret'
database_name 'foo'
privileges [:select,:update,:insert]
action :grant
end
```
Recipes
-------
### ebs_volume
*Note*: This recipe does not currently work on RHEL platforms due to the xfs cookbook not supporting RHEL yet.
Loads the aws information from the data bag. Searches the applications data bag for the database master or slave role and checks that role is applied to the node. Loads the EBS information and the master information from data bags. Uses the aws cookbook LWRP, `aws_ebs_volume` to manage the volume.
On a master node:
- if we have an ebs volume already as stored in a data bag, attach it
- if we don't have the ebs information then create a new one and attach it
- store the volume information in a data bag via a ruby block
On a slave node:
- use the master volume information to generate a snapshot
- create the new volume from the snapshot and attach it
Also on a master node, generate some configuration for running a snapshot via `chef-solo` from cron.
On a new filesystem volume, create as XFS, then mount it in `/mnt`, and also bind-mount it to the mysql data directory (default `/var/lib/mysql`).
### master
This recipe no longer loads AWS specific information, and the database position for replication is no longer stored in a databag because the client might not have permission to write to the databag item. This may be handled in a different way at a future date.
Searches the apps databag for applications, and for each one it will check that the specified database master role is set in both the databag and applied to the node's run list. Then, retrieves the passwords for `root`, `repl` and `debian` users and saves them to the node attributes. If the passwords are not found in the databag, it prints a message that they'll be generated by the mysql cookbook.
Then it adds the application databag database settings to a hash, to use later.
Then it will iterate over the databases and create them with the `mysql_database` resource while adding privileges for application specific database users using the `mysql_database_user` resource.
### slave
_TODO_: Retrieve the master status from a data bag, then start replication using a ruby block. The replication status needs to be handled in some other way for now since the master recipe above doesn't actually set it in the databag anymore.
### snapshot
Run via Chef Solo. Retrieves the db snapshot configuration from the specified JSON file. Uses the `mysql_database` resource to lock and unlock tables, and does a filesystem freeze and EBS snapshot.
Deprecated Recipes
------------------
The following recipe is considered deprecated. It is kept for reference purposes.
### ebs_backup
Older style of doing mysql snapshot and replication using Adam Jacob's [ec2_mysql](http://github.com/adamhjk/ec2_mysql) script and library.
Data Bags
---------
This cookbook uses the apps data bag item for the specified application; see the `application` cookbook's README.md. It also creates data bag items in a bag named 'aws' for storing volume information. In order to interact with EC2, it expects aws to have a main item:
```javascript
{
"id": "main",
"ec2_private_key": "private key as a string",
"ec2_cert": "certificate as a string",
"aws_account_id": "",
"aws_secret_access_key": "",
"aws_access_key_id": ""
}
```
Note: with the Open Source Chef Server, the server using the database recipes must be an admin client or it will not be able to create data bag items. You can modify whether the client is admin by editing it with knife.
knife client edit <client_name>
{
...
"admin": true
...
}
This is not required if the Chef Server is Chef Software Hosted Chef, instead use the ACL feature to modify access for the node to be able to update the data bag.
Usage
-----
Aside from the application data bag (see the README in the application cookbook), create a role for the database master. Use a `role.rb` in your chef-repo, or create the role directly with knife.
```javascript
{
"name": "my_app_database_master",
"chef_type": "role",
"json_class": "Chef::Role",
"default_attributes": {},
"description": "",
"run_list": [
"recipe[mysql::server]",
"recipe[database::master]"
],
"override_attributes": {}
}
```
Create a `production` environment. This is also used in the `application` cookbook.
```javascript
{
"name": "production",
"description": "",
"cookbook_versions": {},
"json_class": "Chef::Environment",
"chef_type": "environment",
"default_attributes": {},
"override_attributes": {}
}
```
The cookbook `my_app_database` is recommended to set up any
application specific database resources such as configuration
templates, trending monitors, etc. It is not required, but you would
need to create it separately in `site-cookbooks`. Add it to the
`my_app_database_master` role.
License & Authors
-----------------
- Author:: Adam Jacob (<adam@chef.io>)
- Author:: Joshua Timberman (<joshua@chef.io>)
- Author:: AJ Christensen (<aj@chef.io>)
- Author:: Seth Chisamore (<schisamo@chef.io>)
- Author:: Lamont Granquist (<lamont@chef.io>)
- Author:: Sean OMeara (<sean@chef.io>)
```text
Copyright 2009-2015, Chef Software, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

View File

@@ -0,0 +1,151 @@
#
# Author:: Douglas Thrift (<douglas.thrift@rightscale.com>)
# Cookbook Name:: database
# Library:: matchers
#
# Copyright 2014, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if defined?(ChefSpec)
# database
#
def create_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:database, :create, resource_name)
end
def drop_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:database, :drop, resource_name)
end
def query_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:database, :query, resource_name)
end
# database user
#
def create_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:database_user, :create, resource_name)
end
def drop_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:database_user, :drop, resource_name)
end
def grant_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:database_user, :grant, resource_name)
end
# mysql database
#
def create_mysql_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:mysql_database, :create, resource_name)
end
def drop_mysql_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:mysql_database, :drop, resource_name)
end
def query_mysql_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:mysql_database, :query, resource_name)
end
# mysql database user
#
def create_mysql_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:mysql_database_user, :create, resource_name)
end
def drop_mysql_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:mysql_database_user, :drop, resource_name)
end
def grant_mysql_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:mysql_database_user, :grant, resource_name)
end
# postgresql database
#
def create_postgresql_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database, :create, resource_name)
end
def drop_postgresql_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database, :drop, resource_name)
end
def query_postgresql_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database, :query, resource_name)
end
# postgresql database schema
#
def create_postgresql_database_schema(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database_schema, :create, resource_name)
end
def drop_postgresql_database_schema(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database_schema, :drop, resource_name)
end
# postgresql database user
#
def create_postgresql_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database_user, :create, resource_name)
end
def drop_postgresql_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database_user, :drop, resource_name)
end
def grant_postgresql_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database_user, :grant, resource_name)
end
def grant_schema_postgresql_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:postgresql_database_user, :grant_schema, resource_name)
end
# sql server database
#
def create_sql_server_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:sql_server_database, :create, resource_name)
end
def drop_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:sql_server_database, :drop, resource_name)
end
def query_database(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:sql_server_database, :query, resource_name)
end
# sql server database user
#
def create_sql_server_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:sql_server_database_user, :create, resource_name)
end
def drop_sql_server_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:sql_server_database_user, :drop, resource_name)
end
def grant_sql_server_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:sql_server_database_user, :grant, resource_name)
end
def alter_roles_sql_server_database_user(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:sql_server_database_user, :alter_roles, resource_name)
end
end

View File

@@ -0,0 +1,158 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Sean OMeara (<sean@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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.
#
class Chef
class Provider
class Database
class Mysql < Chef::Provider::LWRPBase
use_inline_resources if defined?(use_inline_resources)
def whyrun_supported?
true
end
action :create do
# test
schema_present = nil
begin
test_sql = 'SHOW SCHEMAS;'
Chef::Log.debug("#{new_resource.name}: Performing query [#{test_sql}]")
test_sql_results = test_client.query(test_sql)
test_sql_results.each do |r|
schema_present = true if r['Database'] == new_resource.database_name
end
ensure
close_test_client
end
# repair
unless schema_present
converge_by "Creating schema '#{new_resource.database_name}'" do
begin
repair_sql = "CREATE SCHEMA IF NOT EXISTS `#{new_resource.database_name}`"
repair_sql += " CHARACTER SET = #{new_resource.encoding}" if new_resource.encoding
repair_sql += " COLLATE = #{new_resource.collation}" if new_resource.collation
Chef::Log.debug("#{new_resource.name}: Performing query [#{repair_sql}]")
repair_client.query(repair_sql)
ensure
close_repair_client
end
end
end
end
action :drop do
# test
schema_present = nil
begin
test_sql = 'SHOW SCHEMAS;'
Chef::Log.debug("Performing query [#{test_sql}]")
test_sql_results = test_client.query(test_sql)
test_sql_results.each do |r|
schema_present = true if r['Database'] == new_resource.database_name
end
ensure
close_test_client
end
# repair
if schema_present
converge_by "Dropping schema '#{new_resource.database_name}'" do
begin
repair_sql = "DROP SCHEMA IF EXISTS `#{new_resource.database_name}`"
Chef::Log.debug("Performing query [#{repair_sql}]")
repair_client.query(repair_sql)
ensure
close_repair_client
end
end
end
end
action :query do
begin
query_sql = new_resource.sql_query
Chef::Log.debug("Performing query [#{query_sql}]")
query_client.query(query_sql)
ensure
close_query_client
end
end
private
def test_client
require 'mysql2'
@test_client ||=
Mysql2::Client.new(
host: new_resource.connection[:host],
socket: new_resource.connection[:socket],
username: new_resource.connection[:username],
password: new_resource.connection[:password],
port: new_resource.connection[:port]
)
end
def close_test_client
@test_client.close if @test_client
rescue Mysql2::Error
@test_client = nil
end
def repair_client
require 'mysql2'
@repair_client ||=
Mysql2::Client.new(
host: new_resource.connection[:host],
socket: new_resource.connection[:socket],
username: new_resource.connection[:username],
password: new_resource.connection[:password],
port: new_resource.connection[:port]
)
end
def close_repair_client
@repair_client.close if @repair_client
rescue Mysql2::Error
@repair_client = nil
end
def query_client
require 'mysql2'
@query_client ||=
Mysql2::Client.new(
host: new_resource.connection[:host],
socket: new_resource.connection[:socket],
username: new_resource.connection[:username],
password: new_resource.connection[:password],
port: new_resource.connection[:port]
)
end
def close_query_client
@query_client.close
rescue Mysql2::Error
@query_client = nil
end
end
end
end
end

View File

@@ -0,0 +1,193 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Sean OMeara (<sean@chef.io>)
# Copyright:: 2011-2015 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'provider_database_mysql')
class Chef
class Provider
class Database
class MysqlUser < Chef::Provider::Database::Mysql
use_inline_resources if defined?(use_inline_resources)
def whyrun_supported?
true
end
action :create do
# test
user_present = nil
begin
test_sql = "SELECT User,Host from mysql.user WHERE User='#{new_resource.username}' AND Host='#{new_resource.host}';"
test_sql_results = test_client.query(test_sql)
test_sql_results.each do |r|
user_present = true if r['User'] == new_resource.username
end
ensure
close_test_client
end
# repair
unless user_present
converge_by "Creating user '#{new_resource.username}'@'#{new_resource.host}'" do
begin
repair_sql = "CREATE USER '#{new_resource.username}'@'#{new_resource.host}'"
repair_sql += " IDENTIFIED BY '#{new_resource.password}'" if new_resource.password
repair_client.query(repair_sql)
ensure
close_repair_client
end
end
end
end
action :drop do
# test
user_present = nil
begin
test_sql = 'SELECT User,Host'
test_sql += ' from mysql.user'
test_sql += " WHERE User='#{new_resource.username}'"
test_sql += " AND Host='#{new_resource.host}'"
test_sql_results = test_client.query test_sql
test_sql_results.each do |r|
user_present = true if r['User'] == new_resource.username
end
ensure
close_test_client
end
# repair
if user_present
converge_by "Dropping user '#{new_resource.username}'@'#{new_resource.host}'" do
begin
repair_sql = 'DROP USER'
repair_sql += " '#{new_resource.username}'@'#{new_resource.host}'"
repair_client.query repair_sql
ensure
close_repair_client
end
end
end
end
action :grant do
# gratuitous function
def ishash?
return true if (/(\A\*[0-9A-F]{40}\z)/i).match(new_resource.password)
end
db_name = new_resource.database_name ? "`#{new_resource.database_name}`" : '*'
tbl_name = new_resource.table ? new_resource.table : '*'
# Test
incorrect_privs = nil
begin
test_sql = 'SELECT * from mysql.db'
test_sql += " WHERE User='#{new_resource.username}'"
test_sql += " AND Host='#{new_resource.host}'"
test_sql += " AND Db='#{new_resource.database_name}'"
test_sql_results = test_client.query test_sql
incorrect_privs = true if test_sql_results.size == 0
# These should all by 'Y'
test_sql_results.each do |r|
new_resource.privileges.each do |p|
key = "#{p.capitalize}_priv"
incorrect_privs = true if r[key] != 'Y'
end
end
ensure
close_test_client
end
# Repair
if incorrect_privs
converge_by "Granting privs for '#{new_resource.username}'@'#{new_resource.host}'" do
begin
repair_sql = "GRANT #{new_resource.privileges.join(',')}"
repair_sql += " ON #{db_name}.#{tbl_name}"
repair_sql += " TO '#{new_resource.username}'@'#{new_resource.host}' IDENTIFIED BY"
repair_sql += " '#{new_resource.password}'"
repair_sql += ' REQUIRE SSL' if new_resource.require_ssl
repair_sql += ' WITH GRANT OPTION' if new_resource.grant_option
repair_client.query(repair_sql)
repair_client.query('FLUSH PRIVILEGES')
ensure
close_repair_client
end
end
end
end
def action_revoke
db_name = new_resource.database_name ? "`#{new_resource.database_name}`" : '*'
tbl_name = new_resource.table ? new_resource.table : '*'
revoke_statement = "REVOKE #{@new_resource.privileges.join(', ')}"
revoke_statement += " ON #{db_name}.#{tbl_name}"
revoke_statement += " FROM `#{@new_resource.username}`@`#{@new_resource.host}` "
Chef::Log.info("#{@new_resource}: revoking access with statement [#{revoke_statement}]")
db.query(revoke_statement)
@new_resource.updated_by_last_action(true)
ensure
close
end
private
def test_client
require 'mysql2'
@test_client ||=
Mysql2::Client.new(
host: new_resource.connection[:host],
socket: new_resource.connection[:socket],
username: new_resource.connection[:username],
password: new_resource.connection[:password],
port: new_resource.connection[:port]
)
end
def close_test_client
@test_client.close if @test_client
rescue Mysql2::Error
@test_client = nil
end
def repair_client
require 'mysql2'
@repair_client ||=
Mysql2::Client.new(
host: new_resource.connection[:host],
socket: new_resource.connection[:socket],
username: new_resource.connection[:username],
password: new_resource.connection[:password],
port: new_resource.connection[:port]
)
end
def close_repair_client
@repair_client.close if @repair_client
rescue Mysql2::Error
@repair_client = nil
end
end
end
end
end

View File

@@ -0,0 +1,144 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Lamont Granquist (<lamont@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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'
class Chef
class Provider
class Database
class Postgresql < Chef::Provider::LWRPBase
use_inline_resources if defined?(use_inline_resources)
def whyrun_supported?
true
end
def load_current_resource
Gem.clear_paths
require 'pg'
@current_resource = Chef::Resource::Database.new(@new_resource.name)
@current_resource.database_name(@new_resource.database_name)
@current_resource
end
action :create do
unless exists?
begin
encoding = @new_resource.encoding
if encoding != 'DEFAULT'
encoding = "'#{@new_resource.encoding}'"
end
Chef::Log.debug("#{@new_resource}: Creating database #{new_resource.database_name}")
create_sql = "CREATE DATABASE \"#{new_resource.database_name}\""
create_sql += " TEMPLATE = #{new_resource.template}" if new_resource.template
create_sql += " ENCODING = #{encoding}" if new_resource.encoding
create_sql += " TABLESPACE = #{new_resource.tablespace}" if new_resource.tablespace
create_sql += " LC_CTYPE = '#{new_resource.collation}' LC_COLLATE = '#{new_resource.collation}'" if new_resource.collation
create_sql += " CONNECTION LIMIT = #{new_resource.connection_limit}" if new_resource.connection_limit
create_sql += " OWNER = \"#{new_resource.owner}\"" if new_resource.owner
Chef::Log.debug("#{@new_resource}: Performing query [#{create_sql}]")
db('template1').query(create_sql)
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
action :drop do
if exists?
begin
Chef::Log.debug("#{@new_resource}: Dropping database #{new_resource.database_name}")
db('template1').query("DROP DATABASE \"#{new_resource.database_name}\"")
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
action :query do
if exists?
begin
Chef::Log.debug("#{@new_resource}: Performing query [#{new_resource.sql_query}]")
db(@new_resource.database_name).query(@new_resource.sql_query)
Chef::Log.debug("#{@new_resource}: query [#{new_resource.sql_query}] succeeded")
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
private
def exists?
begin
Chef::Log.debug("#{@new_resource}: checking if database #{@new_resource.database_name} exists")
ret = db('template1').query("SELECT * FROM pg_database where datname = '#{@new_resource.database_name}'").num_tuples != 0
ret ? Chef::Log.debug("#{@new_resource}: database #{@new_resource.database_name} exists") :
Chef::Log.debug("#{@new_resource}: database #{@new_resource.database_name} does not exist")
ensure
close
end
ret
end
# Test if text is psql keyword
def keyword?(text)
begin
result = db('template1').exec_params('select * from pg_get_keywords() where word = $1', [text.downcase]).num_tuples != 0
ensure
close
end
result
end
#
# Specifying the database in the connection parameter for the postgres resource is not recommended.
#
# - action_create/drop/exists will use the "template1" database to do work by default.
# - action_query will use the resource database_name.
# - specifying a database in the connection will override this behavior
#
def db(dbname = nil)
close if @db
dbname = @new_resource.connection[:database] if @new_resource.connection[:database]
host = @new_resource.connection[:host]
port = @new_resource.connection[:port] || 5432
user = @new_resource.connection[:username] || 'postgres'
Chef::Log.debug("#{@new_resource}: connecting to database #{dbname} on #{host}:#{port} as #{user}")
password = @new_resource.connection[:password] || node[:postgresql][:password][:postgres]
@db = ::PGconn.new(
host: host,
port: port,
dbname: dbname,
user: user,
password: password
)
end
def close
@db.close rescue nil
@db = nil
end
end
end
end
end

View File

@@ -0,0 +1,74 @@
#
# Author:: Marco Betti (<m.betti@gmail.com>)
# Copyright:: Copyright (c) 2013 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'provider_database_postgresql')
class Chef
class Provider
class Database
class PostgresqlSchema < Chef::Provider::Database::Postgresql
include Chef::Mixin::ShellOut
def load_current_resource
Gem.clear_paths
require 'pg'
@current_resource = Chef::Resource::PostgresqlDatabaseSchema.new(@new_resource.name)
@current_resource.schema_name(@new_resource.schema_name)
@current_resource
end
def action_create
unless exists?
begin
if new_resource.owner
db(@new_resource.database_name).query("CREATE SCHEMA \"#{@new_resource.schema_name}\" AUTHORIZATION \"#{@new_resource.owner}\"")
else
db(@new_resource.database_name).query("CREATE SCHEMA \"#{@new_resource.schema_name}\"")
end
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
def action_drop
if exists?
begin
db(@new_resource.database_name).query("DROP SCHEMA \"#{@new_resource.schema_name}\"")
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
private
def exists?
begin
exists = db(@new_resource.database_name).query("SELECT schema_name FROM information_schema.schemata WHERE schema_name='#{@new_resource.schema_name}'").num_tuples != 0
ensure
close
end
exists
end
end
end
end
end

View File

@@ -0,0 +1,103 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Lamont Granquist (<lamont@chef.io>)
# Author:: Marco Betti (<m.betti@gmail.com>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'provider_database_postgresql')
class Chef
class Provider
class Database
class PostgresqlUser < Chef::Provider::Database::Postgresql
include Chef::Mixin::ShellOut
def load_current_resource
Gem.clear_paths
require 'pg'
@current_resource = Chef::Resource::DatabaseUser.new(@new_resource.name)
@current_resource.username(@new_resource.name)
@current_resource
end
def action_create
unless exists?
begin
options = ''
options += " PASSWORD '#{@new_resource.password}'" if @new_resource.password
options += " #{@new_resource.createdb ? 'CREATEDB' : 'NOCREATEDB'}"
options += " #{@new_resource.createrole ? 'CREATEROLE' : 'NOCREATEROLE'}"
options += " #{@new_resource.login ? 'LOGIN' : 'NOLOGIN'}"
options += " #{@new_resource.replication ? 'REPLICATION' : 'NOREPLICATION'}" if keyword?('REPLICATION')
options += " #{@new_resource.superuser ? 'SUPERUSER' : 'NOSUPERUSER'}"
statement = "CREATE USER \"#{@new_resource.username}\""
if options.length > 0
statement += " WITH #{options}"
end
db('template1').query(statement)
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
def action_drop
if exists?
begin
db('template1').query("DROP USER \"#{@new_resource.username}\"")
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
def action_grant
grant_statement = "GRANT #{@new_resource.privileges.join(', ')} ON DATABASE \"#{@new_resource.database_name}\" TO \"#{@new_resource.username}\""
Chef::Log.info("#{@new_resource}: granting access with statement [#{grant_statement}]")
db(@new_resource.database_name).query(grant_statement)
@new_resource.updated_by_last_action(true)
ensure
close
end
def action_grant_schema
grant_statement = "GRANT #{@new_resource.privileges.join(', ')} ON SCHEMA \"#{@new_resource.schema_name}\" TO \"#{@new_resource.username}\""
Chef::Log.info("#{@new_resource}: granting access with statement [#{grant_statement}]")
db(@new_resource.database_name).query(grant_statement)
@new_resource.updated_by_last_action(true)
ensure
close
end
private
def exists?
begin
exists = db('template1').query("SELECT * FROM pg_user WHERE usename='#{@new_resource.username}'").num_tuples != 0
ensure
close
end
exists
end
end
end
end
end

View File

@@ -0,0 +1,111 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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'
class Chef
class Provider
class Database
class SqlServer < Chef::Provider
include Chef::Mixin::ShellOut
def load_current_resource
Gem.clear_paths
require 'tiny_tds'
@current_resource = Chef::Resource::Database.new(@new_resource.name)
@current_resource.database_name(@new_resource.database_name)
@current_resource
end
def action_create
unless exists?
begin
Chef::Log.debug("#{@new_resource}: Creating database #{new_resource.database_name}")
create_sql = "CREATE DATABASE [#{new_resource.database_name}]"
create_sql += " COLLATE #{new_resource.collation}" if new_resource.collation
db.execute(create_sql).do
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
def action_drop
if exists?
begin
Chef::Log.debug("#{@new_resource}: Dropping database #{new_resource.database_name}")
db.execute("DROP DATABASE [#{new_resource.database_name}]").do
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
def action_query
if exists?
begin
# db.select_db(@new_resource.database_name) if @new_resource.database_name
Chef::Log.debug("#{@new_resource}: Performing query [#{new_resource.sql_query}]")
db.execute(@new_resource.sql_query).do
@new_resource.updated_by_last_action(true)
ensure
close
end
end
end
private
def exists?
exists = false
begin
result = db.execute('SELECT name FROM sys.databases')
result.each do |row|
if row['name'] == @new_resource.database_name
exists = true
break
end
end
result.cancel
ensure
close
end
exists
end
def db
@db ||= begin
::TinyTds::Client.new(
host: @new_resource.connection[:host],
username: @new_resource.connection[:username],
password: @new_resource.connection[:password],
port: @new_resource.connection[:port] || 1433
)
end
end
def close
@db.close rescue nil
@db = nil
end
end
end
end
end

View File

@@ -0,0 +1,152 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'provider_database_sql_server')
class Chef
class Provider
class Database
class SqlServerUser < Chef::Provider::Database::SqlServer
include Chef::Mixin::ShellOut
def load_current_resource
Gem.clear_paths
require 'tiny_tds'
@current_resource = Chef::Resource::DatabaseUser.new(@new_resource.name)
@current_resource.username(@new_resource.name)
@current_resource
end
def action_create
unless exists?(:logins)
if @new_resource.windows_user
db.execute("CREATE LOGIN [#{@new_resource.username}] FROM WINDOWS").do
else
db.execute("CREATE LOGIN [#{@new_resource.username}] WITH PASSWORD = '#{@new_resource.password}', CHECK_POLICY = OFF").do
end
@new_resource.updated_by_last_action(true)
end
unless exists?(:users)
if @new_resource.database_name
Chef::Log.info("#{@new_resource} creating user in '#{@new_resource.database_name}' database context.")
db.execute("USE [#{@new_resource.database_name}]").do
else
Chef::Log.info("#{@new_resource} database_name not provided, creating user in global context.")
end
db.execute("CREATE USER [#{@new_resource.username}] FOR LOGIN [#{@new_resource.username}]").do
@new_resource.updated_by_last_action(true)
end
ensure
close
end
def action_drop
if exists?(:users)
db.execute("DROP USER [#{@new_resource.username}]").do
@new_resource.updated_by_last_action(true)
end
if exists?(:logins)
db.execute("DROP LOGIN [#{@new_resource.username}]").do
@new_resource.updated_by_last_action(true)
end
ensure
close
end
def action_grant
if @new_resource.password || (@new_resource.windows_user && !exists?(:logins))
action_create
end
Chef::Application.fatal!('Please provide a database_name, SQL Server does not support global GRANT statements.') unless @new_resource.database_name
grant_statement = "GRANT #{@new_resource.privileges.join(', ')} ON DATABASE::[#{@new_resource.database_name}] TO [#{@new_resource.username}]"
Chef::Log.info("#{@new_resource} granting access with statement [#{grant_statement}]")
db.execute("USE [#{@new_resource.database_name}]").do
db.execute(grant_statement).do
@new_resource.updated_by_last_action(true)
ensure
close
end
def action_alter_roles
if @new_resource.password || (@new_resource.windows_user && !exists?(:logins))
action_create
end
Chef::Application.fatal!('Please provide a database_name, SQL Server does not support global GRANT statements.') unless @new_resource.database_name
db.execute("USE [#{@new_resource.database_name}]").do
@new_resource.sql_roles.each do | sql_role, role_action |
alter_statement = "ALTER ROLE [#{sql_role}] #{role_action} MEMBER [#{@new_resource.username}]"
Chef::Log.info("#{@new_resource} granting access with statement [#{alter_statement}]")
db.execute(alter_statement).do
end
@new_resource.updated_by_last_action(true)
ensure
close
end
def action_alter_sys_roles
if @new_resource.password || (@new_resource.windows_user && !exists?(:logins))
action_create
end
server_version = db.execute("SELECT SERVERPROPERTY('productversion')").each.first.values.first
Chef::Log.info("SQL Server Version: #{server_version.inspect}")
db.execute('USE [master]').do
@new_resource.sql_sys_roles.each do | sql_sys_role, role_action |
case role_action
when 'ADD'
if server_version < '11.00.0000.00'
alter_statement = "EXEC sp_addsrvrolemember '#{@new_resource.username}', '#{sql_sys_role}'"
else
alter_statement = "ALTER SERVER ROLE #{sql_role} #{role_action} MEMBER [#{@new_resource.username}]"
end
Chef::Log.info("#{@new_resource} granting server role membership with statement [#{alter_statement}]")
when 'DROP'
if server_version < '11.00.0000.00'
alter_statement = "EXEC sp_dropsrvrolemember '#{@new_resource.username}', '#{sql_sys_role}'"
else
alter_statement = "ALTER SERVER ROLE #{sql_role} #{role_action} MEMBER [#{@new_resource.username}]"
end
Chef::Log.info("#{@new_resource} revoking server role membership with statement [#{alter_statement}]")
end
db.execute(alter_statement).do
end
@new_resource.updated_by_last_action(true)
ensure
close
end
private
def exists?(type = :users)
case type
when :users
table = 'database_principals'
if @new_resource.database_name
Chef::Log.debug("#{@new_resource} searching for existing user in '#{@new_resource.database_name}' database context.")
db.execute("USE [#{@new_resource.database_name}]").do
end
when :logins
table = 'server_principals'
end
result = db.execute("SELECT name FROM sys.#{table} WHERE name='#{@new_resource.username}'")
result.each.any?
end
end
end
end
end

View File

@@ -0,0 +1,118 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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'
class Chef
class Resource
class Database < Chef::Resource
def initialize(name, run_context = nil)
super
@resource_name = :database
@database_name = name
@allowed_actions.push(:create, :drop, :query)
@action = :create
end
def database_name(arg = nil)
set_or_return(
:database_name,
arg,
kind_of: String
)
end
def connection(arg = nil)
set_or_return(
:connection,
arg,
required: true
)
end
def sql(arg = nil, &block)
arg ||= block
set_or_return(
:sql,
arg,
kind_of: [String, Proc]
)
end
def sql_query
if sql.is_a?(Proc)
sql.call
else
sql
end
end
def template(arg = nil)
set_or_return(
:template,
arg,
kind_of: String,
default: 'DEFAULT'
)
end
def collation(arg = nil)
set_or_return(
:collation,
arg,
kind_of: String
)
end
def encoding(arg = nil)
set_or_return(
:encoding,
arg,
kind_of: String,
default: 'DEFAULT'
)
end
def tablespace(arg = nil)
set_or_return(
:tablespace,
arg,
kind_of: String,
default: 'DEFAULT'
)
end
def connection_limit(arg = nil)
set_or_return(
:connection_limit,
arg,
kind_of: String,
default: '-1'
)
end
def owner(arg = nil)
set_or_return(
:owner,
arg,
kind_of: String
)
end
end
end
end

View File

@@ -0,0 +1,105 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'resource_database')
class Chef
class Resource
class DatabaseUser < Chef::Resource::Database
def initialize(name, run_context = nil)
super
@resource_name = :database_user
@username = name
@database_name = nil
@table = nil
@host = 'localhost'
@privileges = [:all]
@grant_option = false
@require_ssl = false
@allowed_actions.push(:create, :drop, :grant, :revoke)
@action = :create
end
def database_name(arg = nil)
set_or_return(
:database_name,
arg,
kind_of: String
)
end
def username(arg = nil)
set_or_return(
:username,
arg,
kind_of: String
)
end
def require_ssl(arg = nil)
set_or_return(
:require_ssl,
arg,
kind_of: [TrueClass, FalseClass]
)
end
def password(arg = nil)
set_or_return(
:password,
arg,
kind_of: String
)
end
def table(arg = nil)
set_or_return(
:table,
arg,
kind_of: String
)
end
def host(arg = nil)
set_or_return(
:host,
arg,
kind_of: String
)
end
def privileges(arg = nil)
set_or_return(
:privileges,
arg,
kind_of: Array
)
end
def grant_option(arg = nil)
set_or_return(
:grant_option,
arg,
kind_of: [TrueClass, FalseClass], default: false
)
end
end
end
end

View File

@@ -0,0 +1,32 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Sean OMeara (<sean@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'provider_database_mysql')
class Chef
class Resource
class MysqlDatabase < Chef::Resource::Database
def initialize(name, run_context = nil)
super
@resource_name = :mysql_database
@provider = Chef::Provider::Database::Mysql
end
end
end
end

View File

@@ -0,0 +1,32 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'resource_database_user')
require File.join(File.dirname(__FILE__), 'provider_database_mysql_user')
class Chef
class Resource
class MysqlDatabaseUser < Chef::Resource::DatabaseUser
def initialize(name, run_context = nil)
super
@resource_name = :mysql_database_user
@provider = Chef::Provider::Database::MysqlUser
end
end
end
end

View File

@@ -0,0 +1,33 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Lamont Granquist (<lamont@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'resource_database')
require File.join(File.dirname(__FILE__), 'provider_database_postgresql')
class Chef
class Resource
class PostgresqlDatabase < Chef::Resource::Database
def initialize(name, run_context = nil)
super
@resource_name = :postgresql_database
@provider = Chef::Provider::Database::Postgresql
end
end
end
end

View File

@@ -0,0 +1,43 @@
#
# Author:: Marco Betti (<m.betti@gmail.com>)
# Copyright:: Copyright (c) 2013 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'resource_database')
require File.join(File.dirname(__FILE__), 'provider_database_postgresql_schema')
class Chef
class Resource
class PostgresqlDatabaseSchema < Chef::Resource::Database
def initialize(name, run_context = nil)
super
@resource_name = :postgresql_database_schema
@schema_name = name
@allowed_actions.push(:create, :drop)
@action = :create
@provider = Chef::Provider::Database::PostgresqlSchema
end
def schema_name(arg = nil)
set_or_return(
:schema_name,
arg,
kind_of: String
)
end
end
end
end

View File

@@ -0,0 +1,89 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Lamont Granquist (<lamont@chef.io>)
# Author:: Marco Betti (<m.betti@gmail.com>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'resource_database_user')
require File.join(File.dirname(__FILE__), 'provider_database_postgresql_user')
class Chef
class Resource
class PostgresqlDatabaseUser < Chef::Resource::DatabaseUser
def initialize(name, run_context = nil)
super
@resource_name = :postgresql_database_user
@provider = Chef::Provider::Database::PostgresqlUser
@createdb = false
@createrole = false
@login = true
@replication = false
@superuser = false
@schema_name = nil
@allowed_actions.push(:create, :drop, :grant, :grant_schema)
end
def createdb(arg = nil)
set_or_return(
:createdb,
arg,
equal_to: [true, false]
)
end
def createrole(arg = nil)
set_or_return(
:createrole,
arg,
equal_to: [true, false]
)
end
def login(arg = nil)
set_or_return(
:login,
arg,
equal_to: [true, false]
)
end
def replication(arg = nil)
set_or_return(
:replication,
arg,
equal_to: [true, false]
)
end
def schema_name(arg = nil)
set_or_return(
:schema_name,
arg,
kind_of: String
)
end
def superuser(arg = nil)
set_or_return(
:superuser,
arg,
equal_to: [true, false]
)
end
end
end
end

View File

@@ -0,0 +1,32 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'resource_database')
require File.join(File.dirname(__FILE__), 'provider_database_sql_server')
class Chef
class Resource
class SqlServerDatabase < Chef::Resource::Database
def initialize(name, run_context = nil)
super
@resource_name = :sql_server_database
@provider = Chef::Provider::Database::SqlServer
end
end
end
end

View File

@@ -0,0 +1,63 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright (c) 2011 Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# 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 File.join(File.dirname(__FILE__), 'resource_database_user')
require File.join(File.dirname(__FILE__), 'provider_database_sql_server_user')
class Chef
class Resource
class SqlServerDatabaseUser < Chef::Resource::DatabaseUser
def initialize(name, run_context = nil)
super
@sql_roles = {}
@sql_sys_roles = {}
@resource_name = :sql_server_database_user
@provider = Chef::Provider::Database::SqlServerUser
@allowed_actions.push(:alter_roles, :alter_sys_roles)
@windows_user = false
end
end
def windows_user(arg = nil)
set_or_return(
:windows_user,
arg,
kind_of: [TrueClass, FalseClass],
default: false
)
end
def sql_roles(arg = nil)
Chef::Log.debug("Received roles: #{arg.inspect}")
set_or_return(
:sql_roles,
arg,
kind_of: Hash
)
end
def sql_sys_roles(arg = nil)
Chef::Log.debug("Received Server roles: #{arg.inspect}")
set_or_return(
:sql_sys_roles,
arg,
kind_of: Hash
)
end
end
end

View File

@@ -0,0 +1 @@
{"name":"database","version":"4.0.6","description":"provides LWRPs for common database tasks","long_description":"","maintainer":"Chef Software, Inc.","maintainer_email":"cookbooks@chef.io","license":"Apache 2.0","platforms":{"debian":">= 0.0.0","ubuntu":">= 0.0.0","centos":">= 0.0.0","suse":">= 0.0.0","fedora":">= 0.0.0","redhat":">= 0.0.0","scientific":">= 0.0.0","amazon":">= 0.0.0"},"dependencies":{"postgresql":">= 1.0.0"},"recommendations":{},"suggestions":{},"conflicting":{},"providing":{},"replacing":{},"attributes":{},"groupings":{},"recipes":{}}

View File

@@ -0,0 +1,20 @@
#
# Author:: Jesse Howarth (<him@jessehowarth.com>)
#
# Copyright:: Copyright (c) 2012, Chef Software, Inc. (<legal@chef.io>)
# License:: Apache License, Version 2.0
#
# 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.
#
include_recipe 'postgresql::ruby'

View File

@@ -0,0 +1,8 @@
# Generated by Chef. Local modifications will be overwritten.
<% @db_info.each do |env,db| -%>
# Privileges for databases in <%= env %>
GRANT ALL ON <%= db['database'] %>.* TO '<%= db['username'] %>'@'localhost' IDENTIFIED BY '<%= db['password'] %>';
GRANT ALL ON <%= db['database'] %>.* TO '<%= db['username'] %>'@'<%= node['fqdn'] %>' IDENTIFIED BY '<%= db['password'] %>';
GRANT ALL ON <%= db['database'] %>.* TO '<%= db['username'] %>'@'%' IDENTIFIED BY '<%= db['password'] %>';
<% end -%>
flush privileges;

View File

@@ -0,0 +1,3 @@
AWS_ACCESS_KEY_ID=<%= @access_key %>
AWS_SECRET_ACCESS_KEY=<%= @secret_key %>
BUCKET_BASE_NAME=db-backups

View File

@@ -0,0 +1,6 @@
# Managed by Chef
# m h dom mon dow command
# Keep 1 day of hourly snapshots
PATH=/usr/sbin:/usr/bin:/sbin:/bin
<% cs = "chef-solo -j #{@json_attribs} -c #{@config_file}" %>
<%= @schedule %> root <%= cs %>

View File

@@ -0,0 +1 @@
<%= require 'json'; JSON.pretty_generate(@output) %>

View File

@@ -0,0 +1,6 @@
executable_path ENV['PATH'] ? ENV['PATH'].split(File::PATH_SEPARATOR) : []
<% if @cookbook_path.is_a? Array %>
cookbook_path [ <%= @cookbook_path.collect { |cb| "\"#{cb}\""}.join(", ") -%> ]
<% else %>
cookbook_path "<%= @cookbook_path -%>"
<% end %>

View File

@@ -0,0 +1,2 @@
# Chef Name: ebs_db_backup
15 0 * * * root /usr/local/bin/db-backup.sh

View File

@@ -0,0 +1,8 @@
#!/bin/bash
#
# Back up a MySQL database via EBS snapshot
. /mnt/aws-config/config
/opt/ec2_mysql/bin/ec2_mysql -a $AWS_ACCESS_KEY_ID -s $AWS_SECRET_ACCESS_KEY -p '<%= @mysql_root_passwd %>' -k 5 master
echo "done"

View File

@@ -0,0 +1,10 @@
#!/bin/bash
#
# Restore a MySQL database from EBS
mkdir -p /mnt/restore
. /mnt/aws-config/config
/opt/ec2_mysql/bin/ec2_mysql -a $AWS_ACCESS_KEY_ID -s $AWS_SECRET_ACCESS_KEY -p '<%= @mysql_root_password %>' -v '<%= @ebs_vol_id %>' -m /mnt/restore -d <%= @mysql_device %> -r <%= @mysql_device %> -l debug -n slave
echo "done"

View File

@@ -0,0 +1,27 @@
[default]
access_key = <%= @aws['aws_access_key_id'] %>
acl_public = False
bucket_location = US
debug_syncmatch = False
default_mime_type = binary/octet-stream
delete_removed = False
dry_run = False
encrypt = False
force = False
gpg_command = /usr/bin/gpg
gpg_decrypt = %(gpg_command)s -d --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s
gpg_encrypt = %(gpg_command)s -c --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s
gpg_passphrase =
guess_mime_type = False
host_base = s3.amazonaws.com
host_bucket = %(bucket)s.s3.amazonaws.com
human_readable_sizes = False
preserve_attrs = True
proxy_host =
proxy_port = 0
recv_chunk = 4096
secret_key = <%= @aws['aws_secret_access_key'] %>
send_chunk = 4096
simpledb_host = sdb.amazonaws.com
use_https = True
verbosity = WARNING