Version information
This version is compatible with:
- Puppet Enterprise 2017.2.x, 2017.1.x, 2016.5.x, 2016.4.x
- Puppet >= 3.0.0 < 5.0.0
- , , , ,
Start using this module
Add this module to your Puppetfile:
mod 'TubeMogul-maxscale', '1.1.1'
Learn more about managing modules with a PuppetfileDocumentation
#Maxscale puppet module
####Table of Contents
- Overview
- Module Description - What the module does and why it is useful
- Setup - The basics of getting started with maxscale
- Usage - Configuration options and additional functionality
- To do after you did your setup
- Reference - An under-the-hood peek at what the module is doing and how
##Overview
This module installs and configures the MySQL/MariaDB's binlogs proxy called Maxscale.
GitHub page of the Maxscale project: https://github.com/mariadb-corporation/MaxScale
##Module Description
The idea behind Maxscale is to have slaves that don't really care about which master is behind the replication endpoint. As it's a quite lightweight process, we use several of them on the same instance.
In that spirit, this module allows you to manage several Maxscale instances on the same host very easily.
The module installs the package (from MariaDB's official repositories or from
your own repository if you specify a repo_custom_url
), configures and manages
the one or multiple instances you define in the module's parameters.
Note: We generally use Maxscale as a replication proxy. You should be able to use this module to manage other configuration cases but they have not been tested yet. So if you do and find issues, don't hesitate to file a bug on our github page: https://www.github.com/tubemogul/puppet-maxscale/issues
For more information on the configuration of maxscale as a bilog proxy, see the official documentation: https://mariadb.com/kb/en/mariadb-enterprise/mariadb-maxscale/maxscale-as-a-replication-proxy/
##Setup
##Before you begin
Attention:
To be able to use this module you will have to get the enterprise "Download token".
You can find the token on My Portal in the "Your Subscriptions" section.
Note: If you do not have a MariaDB Enterprise subscription/contract, you can create an account at My Portal, sign the Evaluation Agreement, and try MariaDB Enterprise as an Evaluation User.
###What Maxscale affects
/etc/init.d/maxscale
: used to manage the Maxscale service if you setup the instance 'default'./etc/init.d/maxscale_<instance_name>
: used to manage non-default Maxscale instances./root/.maxadmin
: used to setup the authentication credentials to use with maxadmin. (You can change the directory of the maxadmin file using themaxadmin_config_root
parameter.
Files and directories that you specify in your configuration:
- the Maxscale configuration files
- the Maxscale datadir. The parent directories have to exist before that.
Example: for a datadir set to
/maxscale/default/data
,/maxscale/default
will have to exist prior to the class realization. - the Maxscale cachedir. The parent directories have to exist before that.
- the Maxscale master.ini directory which is basically the same that you set your binlog directory to. The parent directories have to exist before that.
- the Maxscale logdir. The parent directories have to exist before that.
- the Maxscale piddir. The parent directories have to exist before that.
- the folder where the errmsg.sys is stored (generally
/var/lib/maxscale
).
Specific to the Debian OS family:
/etc/apt/sources.list.d/maxscale.list
: used to install themaxscale
package repository (unlessinstall_repository
is set tofalse
).
Setup Requirements
The module requires:
###Beginning with Maxscale
Before you start, make sure you read and complete the Before you begin section.
Once this is done, the module can be used out of the box directly, it just requires Puppetlabs's apt module (if you want to install Maxscale APT repository) and stdlib to be in your modulepath.
The module can be used out of the box directly, it just requires puppetlabs' apt module and puppetlabs' stdlib to be in your modulepath.
To install:
puppet module install TubeMogul/maxscale
Puppet will install the dependencies automatically, but if you want to install the dependencies 1 by 1, you can use this before:
puppet module install puppetlabs/stdlib
puppet module install puppetlabs/apt
##Usage
Those examples include the puppet-only configuration, and the corresponding configuration for those who use hiera (I find it more convenient for copy/paste of a full configuration when you have both - yes, I'm lazy ;-) ).
###Basic example
Let's say that you completed the Before you begin section
and that you ended up with a token that is abc12-34def
. You want to test out
Maxscale with only 1 instance on your server, use the Maxscale APT repository
and all the default parameters. Then your puppet code will just be:
class { 'maxscale':
token => 'abc12-34def',
}
Or just do a simple class { 'maxscale':}
puppet code block and in hiera:
maxscale::token: abc12-34def
###Install without installing a specific repository
If you already have all the repositories installed and you don't want this
module to manage the APT repository on your instance (or that you are using this
module on another OS family than Debian), simply set the
install_repository
parameter to false
.
class { 'maxscale':
install_repository => false,
}
Or just do a simple class { 'maxscale':}
puppet code block and in hiera:
maxscale::install_repository: false
Note: as you don't install the maxscale repository, you don't need the token parameter.
###Using a custom package repository
If you want to use a custom APT package repository, you can use the
repo_custom_url
parameter.
In this case you will want also to set the
repo_fingerprint
with the
fingerprint of your repository and you might also want to change the
repo_keyserver
parameter to specify your own keyserver.
Optionally you can use the repo_repository
and repo_release
to fit your
environment but the default values for those are pretty common values.
class { 'maxscale':
repo_custom_url => 'http://apt.repo.my.company.com',
repo_fingerprint => '1234567890ABCDEF1234567890ABCDEF12345678',
repo_keyserver => 'hkp://keyserver.my.company.com:8080',
repo_repository => 'optionals',
}
Or just do a simple class { 'maxscale':}
puppet code block and in hiera:
maxscale::repo_custom_url: http://apt.repo.my.company.com
maxscale::repo_fingerprint: 1234567890ABCDEF1234567890ABCDEF12345678
maxscale::repo_keyserver: hkp://keyserver.my.company.com:8080
maxscale::repo_repository: optionals
Note: as you don't install the maxscale repository, you don't need the token parameter.
###Specify a version
Let's say that you completed the Before you begin section
and that you ended up with a token that is abc12-34def
.
By default this module installs the latest version of the package (it doesn't upgrade automatically when a new version is out, that would be really bad in a production environment if it did! :) )
You want now to have a specific older version to install because you haven't
finished benchmarking the new one. Then you would use the
repo_version
parameter for that purpose.
Here's what you would use (if you use all the default for the rest):
class { 'maxscale':
token => 'abc12-34def',
repo_version => '1.2'
}
Or just do a simple class { 'maxscale':}
puppet code block and in hiera:
maxscale::token: abc12-34def
maxscale::repo_version: 1.2
###Working with a single instance
Let's say that you completed the Before you begin section
and that you ended up with a token that is abc12-34def
.
Now let's say that you want to customize some parts of your Maxscale installation. For example, you want your instance setup to have:
- cachedir to be
/maxscale/cache
, - datadir to be
/maxscale/data
, - 4 threads instead of 2
- the
server-id
set to 55 - an additional binlog router option
binlogdir
set to/maxscale/binlog
- a different password (of course! :) )
- a master which is 10.0.0.10
Note: It is not mandatory to set the ensure
, logdir
, piddir
, svcuser
, svcgroup
,
errmsgsys_path
and configfile
parameters as they have default values, but I like to set
them just to clarify for the user that is not 100% familiar with the instance, what values they have.
class { 'maxscale':
token => 'abc12-34def',
services_conf => {
'default' => {
ensure => 'running',
logdir => '/var/log/maxscale',
cachedir => '/maxscale/cache',
datadir => '/maxscale/data',
piddir => '/var/run/maxscale',
svcuser => 'maxscale',
svcgroup => 'maxscale',
errmsgsys_path => '/var/lib/maxscale',
configfile => '/etc/maxscale.cnf',
'config' => {
'maxscale' => {
'threads' => 4
},
'Binlog_Service' => {
'type' => 'service',
'router' => 'binlogrouter',
'router_options' => 'mariadb10-compatibility=1,server-id=55,binlogdir=/maxscale/binlog',
'user' => 'maxscale',
'passwd' => 'AR3allyRe@llyG0odPwd...',
'version_string' => '10.1.12-MariaDB-1~trusty',
},
'Binlog Listener' => {
'type' => 'listener',
'service' => 'Binlog_Service',
'protocol' => 'MySQLClient',
'port' => 3310,
},
'Debug Interface' => {
'type' => 'service',
'router' => 'debugcli',
},
'CLI' => {
'type' => 'service',
'router' => 'cli',
},
'Debug Listener' => {
'type' => 'listener',
'service' => 'Debug Interface',
'protocol' => 'telnetd',
'address' => '127.0.0.1',
'port' => 4442,
},
'CLI Listener' => {
'type' => 'listener',
'service' => 'CLI',
'protocol' => 'maxscaled',
'port' => 6603,
},
},
'master_ini' => {
'directory' => '/maxscale/binlog',
'content' => {
'binlog_configuration' => {
'master_host' => '10.0.0.10',
'master_port' => 3306,
'master_user' => 'maxscale',
'master_password' => 'PLEASE_CHANGE_ME!3!',
'filestem' => 'mysql-bin',
},
},
},
}
}
Or just do a simple class { 'maxscale':}
puppet code block and in hiera:
maxscale::token: abc12-34def
maxscale::services_conf:
default:
ensure: running
logdir: /var/log/maxscale
cachedir: /maxscale/cache
datadir: /maxscale/data
piddir: /var/run/maxscale
svcuser: maxscale
svcgroup: maxscale
errmsgsys_path: /var/lib/maxscale
configfile: /etc/maxscale.cnf
config:
maxscale:
threads: 4
Binlog_Service:
type: service
router: binlogrouter
router_options: 'mariadb10-compatibility=1,server-id=55,binlogdir=/maxscale/binlog'
user: maxscale
passwd: 'AR3allyRe@llyG0odPwd...'
version_string: '10.1.12-MariaDB-1~trusty'
Binlog Listener:
type: listener
service: Binlog_Service
protocol: MySQLClient
port: 3310
Debug Interface:
type: service
router: debugcli
CLI:
type: service
router: cli
Debug Listener:
type: listener
service: 'Debug Interface'
protocol: telnetd
address: 127.0.0.1
port: 4442
CLI Listener:
type: listener
service: CLI
protocol: maxscaled
port: 6603
master_ini:
director: /maxscale/binlog
content:
binlog_configuration:
master_host: 10.0.0.10
master_port: 3306
master_user: maxscale
master_password: PLEASE_CHANGE_ME!3!
filestem: mysql-bin
###Working in a multi-instance environment
Let's say that you completed the Before you begin section
and that you ended up with a token that is abc12-34def
.
Now let's say that you want to replicate 2 data streams from 2 different masters. To do that you will need 2 Maxscale instances that you can in our case install on the same sever. For each instance, we will use the same kind of parameters as previously.
For the example, let's continue to use the default instance to replicate from a
master named foo
and let's have anoter one for the master named bar
.
For example, you want your instance setup to have:
- logdir to be:
/var/log/maxscale/<master_name>
, - cachedir to be
/maxscale/cache/<master_name>
, - datadir to be
/maxscale/data/<master_name>
, - piddir to be
/var/run/maxscale/<master_name>
, - configfile to be
/etc/maxscale/<master_name>.cfg
, - the
server-id
set to 55 and 66 - an additional binlog router option
binlogdir
set to/maxscale/binlog/<master_name>
- a different password (of course! :) )
- foo master IP is 10.0.0.10 and bar master is 10.0.0.11
The debug listener service has been removed in this example as it's not mandatory.
class { 'maxscale':
token => 'abc12-34def',
services_conf => {
'default' => {
logdir => '/var/log/maxscale/foo',
cachedir => '/maxscale/cache/foo',
datadir => '/maxscale/data/foo',
piddir => '/var/run/maxscale/foo',
configfile => '/etc/maxscale/foo.cnf',
'config' => {
'maxscale' => {
'threads' => 2
},
'Binlog_Service' => {
'type' => 'service',
'router' => 'binlogrouter',
'router_options' => 'mariadb10-compatibility=1,server-id=55,binlogdir=/maxscale/binlog/foo',
'user' => 'maxscale',
'passwd' => 'AR3allyRe@llyG0odPwd...',
'version_string' => '10.1.12-MariaDB-1~trusty',
},
'Binlog Listener' => {
'type' => 'listener',
'service' => 'Binlog_Service',
'protocol' => 'MySQLClient',
'port' => 3310,
},
'CLI' => {
'type' => 'service',
'router' => 'cli',
},
'CLI Listener' => {
'type' => 'listener',
'service' => 'CLI',
'protocol' => 'maxscaled',
'port' => 6603,
},
},
'master_ini' => {
'directory' => '/maxscale/binlog/foo',
'content' => {
'binlog_configuration' => {
'master_host' => '10.0.0.10',
'master_port' => 3306,
'master_user' => 'maxscale',
'master_password' => 'PLEASE_CHANGE_ME!3!',
'filestem' => 'mysql-bin',
},
},
},
}
'bar' => {
logdir => '/var/log/maxscale/bar',
cachedir => '/maxscale/cache/bar',
datadir => '/maxscale/data/bar',
piddir => '/var/run/maxscale/bar',
configfile => '/etc/maxscale/bar.cnf',
'config' => {
'maxscale' => {
'threads' => 2
},
'Binlog_Service' => {
'type' => 'service',
'router' => 'binlogrouter',
'router_options' => 'mariadb10-compatibility=1,server-id=66,binlogdir=/maxscale/binlog/bar',
'user' => 'maxscale',
'passwd' => 'AR3allyRe@llyG0odPwd...',
'version_string' => '10.1.12-MariaDB-1~trusty',
},
'Binlog Listener' => {
'type' => 'listener',
'service' => 'Binlog_Service',
'protocol' => 'MySQLClient',
'port' => 3311,
},
'CLI' => {
'type' => 'service',
'router' => 'cli',
},
'CLI Listener' => {
'type' => 'listener',
'service' => 'CLI',
'protocol' => 'maxscaled',
'port' => 6604,
},
},
'master_ini' => {
'directory' => '/maxscale/binlog/bar',
'content' => {
'binlog_configuration' => {
'master_host' => '10.0.0.11',
'master_port' => 3306,
'master_user' => 'maxscale',
'master_password' => 'PLEASE_CHANGE_ME!3!',
'filestem' => 'mysql-bin',
},
},
},
}
}
Or just do a simple class { 'maxscale':}
puppet code block and in hiera:
maxscale::token: abc12-34def
maxscale::services_conf:
default:
logdir: /var/log/maxscale/foo
cachedir: /maxscale/cache/foo
datadir: /maxscale/data/foo
piddir: /var/run/maxscale/foo
configfile: /etc/maxscale/foo.cnf
config:
maxscale:
threads: 2
Binlog_Service:
type: service
router: binlogrouter
router_options: 'mariadb10-compatibility=1,server-id=55,binlogdir=/maxscale/binlog/foo'
user: maxscale
passwd: 'AR3allyRe@llyG0odPwd...'
version_string: '10.1.12-MariaDB-1~trusty'
Binlog Listener:
type: listener
service: Binlog_Service
protocol: MySQLClient
port: 3310
CLI:
type: service
router: cli
CLI Listener:
type: listener
service: CLI
protocol: maxscaled
port: 6603
master_ini:
directory: /maxscale/binlog
content:
binlog_configuration:
master_host: 10.0.0.10
master_port: 3306
master_user: maxscale
master_password: PLEASE_CHANGE_ME!3!
filestem: mysql-bin
bar:
logdir: /var/log/maxscale/bar
cachedir: /maxscale/cache/bar
datadir: /maxscale/data/bar
piddir: /var/run/maxscale/bar
configfile: /etc/maxscale/bar.cnf
config:
maxscale:
threads: 2
Binlog_Service:
type: service
router: binlogrouter
router_options: 'mariadb10-compatibility=1,server-id=66,binlogdir=/maxscale/binlog/bar'
user: maxscale
passwd: 'AR3allyRe@llyG0odPwd...'
version_string: '10.1.12-MariaDB-1~trusty'
Binlog Listener:
type: listener
service: Binlog_Service
protocol: MySQLClient
port: 3311
CLI:
type: service
router: cli
CLI Listener:
type: listener
service: CLI
protocol: maxscaled
port: 6604
master_ini:
directory: /maxscale/binlog
content:
binlog_configuration:
master_host: 10.0.0.10
master_port: 3306
master_user: maxscale
master_password: PLEASE_CHANGE_ME!3!
filestem: mysql-bin
##To do after you did your setup
###Tell maxscale where to start when working as a replication proxy
It is important to keep in mind that maxscale expects the master to have a
a binlog file #1 (mysql-bin.000001) to start the replication automatically.
If you want to download the binlogs from an server that has been running for a
long time, you will need to set the master binlog position using the CHANGE MASTER TO
command as specified in: https://mariadb.com/kb/en/mariadb-enterprise/mariadb-maxscale/maxscale-as-a-replication-proxy/#master-server-setupchange
Dirty hack: let's say your binlog directory is /maxscale/binlogs
and that
you want your maxscale server to start at the binlog: mysql-bin.734568
, you
can create a file /maxscale/binlogs/mysql-bin.734568
on the maxscale server
(the file must be owned by the maxscale user) and restart the maxscale service.
As long as the binlog is available on the master, maxscale will start
downloading the binlogs from there.
###Setup a cron to cleanup the binlogs when using a replication proxy
There is no automatic cleanup of the binlogs currently in maxscale and this module don't have a binlog cleanup either.
You can add one to your profile based on this example:
cron {'binlog_cleanup_instance01':
command => 'find /maxscale/binlogs -type f -name \'mysql-bin.[0-9][0-9][0-9]*\' -mtime +6 -delete',
user => 'maxscale',
hour => '*',
minute => '10',
}
Why is it not implemented yet in this module?
Your binlogs name can vary (depending on your master file name and the filestem parameter in your master.ini), and you can use maxscale for other usages than a replication proxy, so it seemed overkill for now to add a crontab to cleanup the binlogs.
##Reference
###Public classes
maxscale
: Installs, configures and manages one or serveral maxscale instances on a single server.
###Private classes
maxscale::install
: Installs the maxscale repository and themaxscale
package.maxscale::config
: Configures the .maxadmin file in /root.maxscale::install
: Installs the repository (ifinstall_repository
is set totrue
) and themaxscale
package.maxscale::params
: Sets the default values that you can overwrite directly by setting the parameters of themaxscale
class.
###Parameters
####Class maxscale
install_repository
This parameter is a boolean that defines whether you will install the APT repository on your server or not.
Default: true
token
Required if install_repository
is set to true
or repo_custom_url
is not set.
It is used to construct the download url in the repository.
For more information, see the Before you begin section.
Default: undef
repo_custom_url
Required if no token
is specified. Use this parameter if you want to download the package from a custom repository.
Default: undef
repo_version
This is used to contruct the url of the repository to provide the right version
of the package. Unused when install_repository
is set to false
or when
repo_custom_url
is set.
Default: latest
repo_release
Usual repository release
field on a classic APT repository.
Defaults to the lsbdistcodename
fact.
repo_repository
Usual repository repository
field on a classic APT repository.
Default: main
repo_fingerprint
Full fingerprint of the key used to authenticate the APT repository.
For more information on secure apt repository, see: https://help.ubuntu.com/community/SecureApt
Default: 13CFDE6DD9EE9784F41AF0F670E4618A8167EE24
repo_keyserver
Keyserver to use to retrieve your repository key.
For more information on secure apt repository, see: https://help.ubuntu.com/community/SecureApt
Default: hkp://keyserver.ubuntu.com:80
package_name
Name of the package to use to install Maxscale.
Default: maxscale
maxadmin_config_root
Path of the root home directory where to install the .maxadmin
file to use to
authenticate on the maxscale instances using maxadmin.
Default: /root
instance_user
User to put in the .maxadmin
to use with the maxadmin tool.
Default: maxscale
instance_password
Password to put in the .maxadmin
to use with the maxadmin tool.
Default: mariadb
services_conf
This is a hash containing:
- on the 1st level, the keys are the name of the instances. If you use just one, you will probably want to just use 'default' there. The values contain the configuration parameters corresponding to the instance.
- Inside the configuration parameters, you have:
ensure
: used to force a service to run or to stoplogdir
: will setup the --logdir parameter on the Maxscale service (and will create the directory if doesn't exists)cachedir
: will setup the --cachedir parameter on the Maxscale service (and will create the directory if doesn't exists)datadir
: will setup the --datadir parameter on the Maxscale service (and will create the directory if doesn't exists)piddir
: will setup the --piddir parameter on the Maxscale service (and will create the directory if doesn't exists)svcuser
: OS user to run the service undersvcgroup
: OS group to use to set on the directories managed by the serviceerrmsgsys_path
: will setup the --language parameter on the Maxscale service (to specify the path of the errmsg.sys file)configfile
: path of the configuration file to be created and used for your instanceconfig
: contains a hash which will define the content of the Maxscale configuration file. Each key represents a section, and each key has a value, which is represented like:key => value
master_ini
: which is a hash contructed with:directory
: the directory that will contain the master.ini file (should be the same as the binlog)content
: contains a hash which will define the content of the master.ini file. Each key represents a section, and each key has a value, which is represented like:key => value
Default:
{
'default' => {
ensure => 'running',
logdir => '/var/log/maxscale',
cachedir => '/var/cache/maxscale',
datadir => '/var/cache/maxscale',
piddir => '/var/run/maxscale',
svcuser => 'maxscale',
svcgroup => 'maxscale',
errmsgsys_path => '/var/lib/maxscale',
configfile => '/etc/maxscale.cnf',
config => {
'maxscale' => {
'threads' => 2
},
'Binlog_Service' => {
'type' => 'service',
'router' => 'binlogrouter',
'router_options' => 'mariadb10-compatibility=1,server-id=10,binlogdir=/var/cache/maxscale/binlog',
'user' => 'maxscale',
'passwd' => 'PLEASE_CHANGE_ME!1!',
'version_string' => '10.1.12-MariaDB-1~trusty',
},
'Binlog Listener' => {
'type' => 'listener',
'service' => 'Binlog_Service',
'protocol' => 'MySQLClient',
'port' => 3310,
},
'Debug Interface' => {
'type' => 'service',
'router' => 'debugcli',
},
'CLI' => {
'type' => 'service',
'router' => 'cli',
},
'Debug Listener' => {
'type' => 'listener',
'service' => 'Debug Interface',
'protocol' => 'telnetd',
'address' => '127.0.0.1',
'port' => 4442,
},
'CLI Listener' => {
'type' => 'listener',
'service' => 'CLI',
'protocol' => 'maxscaled',
'port' => 6603,
},
},
'master_ini' => {
'directory' => '/var/cache/maxscale/binlog',
'content' => {
'binlog_configuration' => {
'master_host' => '127.0.0.1',
'master_port' => 3306,
'master_user' => 'maxscale',
'master_password' => 'PLEASE_CHANGE_ME!3!',
'filestem' => 'mysql-bin',
},
},
},
}
}
##Limitations
This module has been tested against Puppet 3.8 with Ubuntu clients with Maxscale 10.1.
The spec tests work on Puppet 3.x and 4.x.
To work on Debian OS family servers, it requires the apt module from Puppetlabs to be installed if you want to have this module manage your maxscale repository.
The implementation for the installation on other operating systems has not been done yet but should be pretty straightforward to do. Just ask which one you want and we'll add it or submit a pull request on our github page and we'll integrate it.
##Development
See the CONTRIBUTING.md file.
Change Log
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
[1.1.1] - 2017-01-30
Changed
- Move the changelog to markdown and start using semver
- The Travis tests matrix has been changed to get quicker tests and integrate rubocop testing for code quality
Gemfile
andRakefile
have been refactored- Added the syntax color for the code blocks in the
README.markdown
Fixed
- Code quality cleanup based on rubocop and rubocop-spec standards
- Fixed puppet-lint warnings
Dropped
- Removed the
CONTRIBUTORS
file. You can get the contributors via the GitHub API - The version-dependent files have been dropped (aka
Gemfile.lock
)
[1.1.0] - 2016-10-13
Added
- Added initial support for osfamily RedHat.
- Upgrade to latest puppet-skeleton version from garethr
Fixed
- Create directories when maxscale user exists
[1.0.2] - 2016-08-18
Changed
- Updating documentation
Fixed
- Fixing a wrong dependency in the metadata
[1.0.1] - 2016-08-18
Added
- Add documentation to guide on the last steps of the process for creating a binlog proxy
Fixed
- fix some ports in the multi-instance example
- Fix some spec issues appeared with newly used fact on the apt module
- Fixing missing execution rights on the init script
- Fixing
json_pure
dependency problems in theGemfile
- Fix a mistake in the installation part of the documentation
[1.0.0] - 2016-04-26
Added
- 1st public version of the module
Dependencies
- puppetlabs/apt (>= 2.0.0 < 3.0.0)
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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.