Version information
This version is compatible with:
- Puppet Enterprise 2023.2.x, 2023.1.x, 2023.0.x, 2021.7.x, 2021.6.x, 2021.5.x, 2021.4.x, 2021.3.x, 2021.2.x, 2021.1.x, 2021.0.x, 2019.8.x, 2019.7.x, 2019.5.x, 2019.4.x, 2019.3.x, 2019.2.x, 2019.1.x, 2019.0.x
- Puppet >= 6.0.0 < 8.0.0
- , , , , , , ,
Tasks:
- install_kb
Start using this module
Add this module to your Puppetfile:
mod 'puppetlabs-patching_as_code', '0.6.2'
Learn more about managing modules with a PuppetfileDocumentation
puppetlabs-patching_as_code
Table of Contents
- puppetlabs-patching_as_code
- [Table of Contents](#table-of-contents)
Description
This module provides automatic patch management for Linux and Windows through desired state code.
Setup
What this module affects
This module will leverage the fact data provided by either the albatrossflavour/os_patching or PE 2019.8's builtin pe_patch
module.
Once available patches are known via the above facts, the module will install the patches during the configured patch window.
- For Linux operating systems, this happens through the native Package resource.
- For Windows operating systems, this happens through the
patching_as_code::kb
class, which comes with this module. - By default, a reboot is only performed when necessary at the end of a patch run that actually installed patches. You can change this behavior though, to either always reboot or never reboot.
- You can define pre-patch, post-patch and pre-reboot commands for patching runs. We recommend that for Windows, you use Powershell-based commands for these. Specifically for pre-reboot commands on Windows, you must use Powershell-based commands.
- This module will report the configuration for each node in a
patching_as_code_config
fact
Setup Requirements
To start with patching_as_code, complete the following prerequirements:
- Ensure this module and its dependencies are added to your control repo's Puppetfile
- If you are not running Puppet Enterprise 2019.8.0 or higher, you'll also need to add the albatrossflavour/os_patching module to your control repo's Puppetfile
- If you are running Puppet Enterprise 2019.8.0 or higher, the built-in
pe_patch
module will be used by default. You can however force the use of theos_patching
module if so desired, by setting the optionalpatching_as_code::use_pe_patch
parameter tofalse
. To prevent duplicate declarations of thepe_patch
class in PE 2019.8.0+, this module will default to NOT declaring thepe_patch
class. This allows you to use the builtin "PE Patch Management" classification groups to classifype_patch
. If you however would like this module to control the classification ofpe_patch
for you (and sync thepatch_group
parameter), please set thepatching_as_code::classify_pe_patch
parameter totrue
. - For Linux operating systems, ensure your package managers are pointing to repositories that are publishing new package versions as needed
- For Windows operating systems, ensure Windows Update is configured to check with a valid update server (either WSUS, Windows Update or Microsoft Update). If you want, you can use the puppetlabs/wsus_client module to manage the Windows Update configuration.
Beginning with patching_as_code
To get started with the patching_as_code module, include it in your manifest:
include patching_as_code
or
class {'patching_as_code':}
This enables automatic detection of available patches, and puts all the nodes in the primary
patch group.
By default this will patch your systems on the 3rd Friday of the month, between 22:00 and midnight (00:00), and perform a reboot if necessary.
On PE 2019.8 or newer this will not automatically classify the pe_patch
class, so that you can control this through PE's builtin "PE Patch Management" node groups.
To allow patching_as_code to control & declare the pe_patch
class, change the declaration to:
class {'patching_as_code':
classify_pe_patch => true
}
This will change the behavior to also declare the pe_patch
class, and match its patch_group
parameter with this module's patch_group
parameter. In this scenario, make sure you do not classify your nodes with pe_patch
via the "PE Patch Management" node groups or other means.
Usage
To control which patch group(s) a node belongs to, you need to set the patch_group
parameter of the class.
It is highly recommended to use Hiera to set the correct value for each node, for example:
patching_as_code::patch_group: early
The module provides 6 patch groups out of the box:
weekly: patches each Thursday of the month, between 09:00 and 11:00, performs a reboot if needed
testing: patches every 2nd Thursday of the month, between 07:00 and 09:00, performs a reboot if needed
early: patches every 3rd Monday of the month, between 20:00 and 22:00, performs a reboot if needed
primary: patches every 3rd Friday of the month, between 22:00 and 00:00, performs a reboot if needed
secondary: patches every 3rd Saturday of the month, between 22:00 and 00:00, performs a reboot if needed
late: patches every 4th Saturday of the month, between 22:00 and 00:00, performs a reboot if needed
There are also 2 special built-in patch groups:
always: patches immediately when a patch is available, can patch in any agent run, performs a reboot if needed
never: never performs any patching and does not reboot
If you want to assign a node to multiple patch groups, specify an array of values in Hiera:
patching_as_code::patch_group:
- testing
- early
or, in flow style:
patching_as_code::patch_group: [ testing, early ]
Note: if you assign a node to multiple patch groups, the value for the patch group provided to pe_patch
/os_patching
will be a space-separated list of the assigned patch groups. This is because pe_patch
/os_patching
do not natively support multiple patch groups, so we work around this by converting our list a single string that pe_patch
/os_patching
can work with. This is purely for cosmetic purposes and does not affect the functionality of either solution.
Customizing the patch groups
You can customize the patch groups to whatever you need. To do so, simply copy the patching_as_code::patch_schedule
hash from the data/common.yaml
in this module, and paste it into your own Hiera store (recommended to place it in your Hiera's own common.yaml
). This Hiera value will now override the defaults that the module provides. Customize the hash to your needs.
The hash has the following structure:
patching_as_code::patch_schedule:
<name of patch group>:
day_of_week: <day to patch systems>
count_of_week: <the Nth time day_of_week occurs in the month>
hours: <start of patch window> - <end of patch window>
max_runs: <max number of times that Puppet can perform patching within the patch window>
reboot: always | never | ifneeded
For example, say you want to have the following 2 patch groups:
group1: patches every 2nd Sunday of the month, between 10:00 and 11:00, max 1 time, reboots if needed
group2: patches every 3nd and 4th Monday of the month, between 20:00 and 22:00, max 3 times, does not reboot
group3: patches every day in the 3rd week of the month, between 18:00 and 20:00, max 4 times, always reboots
then define the hash as follows:
patching_as_code::patch_schedule:
group1:
day_of_week: Sunday
count_of_week: 2
hours: 10:00 - 11:00
max_runs: 1
reboot: ifneeded
group2:
day_of_week: Monday
count_of_week: [3,4]
hours: 20:00 - 22:00
max_runs: 3
reboot: never
group3:
day_of_week: Any
count_of_week: 3
hours: 18:00 - 20:00
max_runs: 4
reboot: always
Controlling which patches get installed
If you need to limit which patches can get installed, use the blocklist/allowlist capabilties. This is best done through Hiera by defining an array values for patching_as_code::blocklist
and/or patching_as_code::allowlist
.
To prevent KB2881685 from getting installed:
patching_as_code::blocklist:
- KB2881685
To only allow the installation of a specific set of 3 KB articles:
patching_as_code::allowlist:
- KB123456
- KB234567
- KB345678
Both options can be combined, in that case the list of available updates first gets reduced to the what is allowed by the allowlist, and then gets further reduced by any blocklisted updates.
Defining situations when patching needs to be skipped
There could be situations where you don't want patching to occur if certain conditions are met. This module supports two such situations:
- A specific process is running that must not be interrupted by patching
- The node to be patched is currently connected via a metered link (Windows only)
Managing unsafe processes for patching
You can define a list of unsafe processes which, if any are found to be active on the node, should cause patching to be skipped. This is best done through Hiera, by defining an array value for patching_as_code::unsafe_process_list
.
To skip patching if application1
or application2
is among the active processes:
patching_as_code::unsafe_process_list:
- application1
- application2
This works on both Linux and Windows, and the matching is done case-insensitive. If one process from the unsafe_process_list is found as an active process, patching will be skipped.
Managing patching over metered links (Windows only)
By default, this module will not perform patching over metered links (e.g. 3G/4G connections). You can control this behavior through the patch_on_metered_links
parameter. To force patching to occur even over metered links, either define this value in Hiera:
patching_as_code::patch_on_metered_links: true
or set this parameter as part of calling the class:
class {'patching_as_code':
patch_on_metered_links => true
}
Defining pre/post-patching and pre-reboot commands
You can control additional commands that get executed at specific times, to facilitate the patch run. For example, you may want to shutdown specific applications before patching, or drain a kubernetes node before rebooting. The order of operations is as follows:
1) If reboots are enabled, check for pending reboots and reboot system immediately if a pending reboot is found
2) Run pre-patching commands
3) Install patches
4) Run post-patching commands
5) If reboots are enabled, run pre-reboot commands (if a reboot is pending, or when reboots are set to always
)
6) If reboots are enabled, reboot system (if a reboot is pending, or when reboots are set to always
)
To define the pre/post-patching and pre-reboot commands, you need to create hashes in Hiera. The commands will be executed as Exec
resources, and you can use any of the allowed attributes for that resource (just don't use metaparameters). There are 3 hashes you can define:
patching_as_code::pre_patch_commands
patching_as_code::post_patch_commands
patching_as_code::pre_reboot_commands
It's best to define this in Hiera, so that the commands can be tailored to individual nodes or groups of nodes. A hash for a command (let's use pre-reboot as an example) looks like this in Hiera:
patching_as_code::pre_reboot_commands:
prep k8s for reboot:
command: /usr/bin/kubectl drain k8s-3.company.local --ignore-daemonsets --delete-local-data
Here's another example, this time for a pre-patch powershell command on Windows:
patching_as_code::pre_patch_commands:
shutdown SQL server:
command: Stop-Service MSSQLSERVER -Force
provider: powershell
As you can see, it's just like defining Exec
resources.
Note that specifically for patching_as_code::pre_reboot_commands
, the provider:
, onlyif:
and unless:
parameters will be ignored, as these are overwritten by the internal logic to detect pending reboots. On Linux the provider:
is forced to posix
, on Windows it is forced to powershell
.
Limitations
This solution will patching to initiate whenever an agent run occurs inside the patch window. On Windows, patch runs for Cumulative Updates can take a long time, so you may want to tune the hours of your patch windows to account for a patch run getting started near the end of the window and still taking a significant amount of time.
Reference
Table of Contents
Classes
patching_as_code
: Framework for patch management as code. Works alongside the puppetlabs/pe_patch or albatrossflavour/os_patching modules
Classes
patching_as_code
Framework for patch management as code. Works alongside the puppetlabs/pe_patch or albatrossflavour/os_patching modules
Examples
Using the module with defaults, or controlling options through Hiera
include patching_as_code
Forcing the classification of pe_patch on PE 2019.8.0+
class {'patching_as_code':
classify_pe_patch => true
}
Forcing the use of albatrossflavour/os_patching on PE 2019.8.0+
class {'patching_as_code':
use_pe_patch => false
}
Parameters
The following parameters are available in the patching_as_code
class.
patch_group
Data type: Variant[String,Array[String]]
Name(s) of the patch_group(s) for this node. Must match one or more of the patch groups in $patch_schedule To assign multiple patch groups, provide this parameter as an array
patch_schedule
Data type: Hash
Hash of available patch_schedules. Default schedules are in /data/common.yaml of this module
Options:
- :day_of_week
String
: Day of the week to patch, valid options: 'Any', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' - :count_of_week
Variant[Integer,Array[Integer]]
: Which week(s) in the month to patch, use number(s) between 1 and 5 - :hours
String
: Which hours on patch day to patch, define a range as 'HH:MM - HH:MM' - :max_runs
String
: How many Puppet runs during the patch window can Puppet install patches. Must be at least 1. - :reboot
String
: Reboot behavior, valid options: 'always', 'never', 'ifneeded'
blocklist
Data type: Array
List of updates to block from installing
allowlist
Data type: Array
List of updates that are allowed to be installed. Any updates not on this list get blocked.
unsafe_process_list
Data type: Array
List of processes that will cause patching to be skipped if any of the processes in the list are active on the system.
pre_patch_commands
Data type: Hash
Hash of command to run before patching
Options:
- :command
String
: The pre-patching command to execute - :path
String
: The path for the command - :provider
String
: The provider for the command
post_patch_commands
Data type: Hash
Hash of command to run after patching
Options:
- :command
String
: The post-patching command to execute - :path
String
: The path for the command - :provider
String
: The provider for the command
pre_reboot_commands
Data type: Hash
Hash of command to run before rebooting
Options:
- :command
String
: The pre-reboot command to execute - :path
String
: The path for the command
Note: the provider for the command gets forced to posix
on Linux and powershell
on Windows
plan_patch_fact
Data type: Optional[String]
Reserved parameter for running patching_as_code
via a Plan (future functionality).
Default value: undef
enable_patching
Data type: Optional[Boolean]
Controls if patching_as_code
is allowed to install any updates. Can be used to disable patching with a single override.
Default value: true
security_only
Data type: Optional[Boolean]
Install only security updates. This works for Linux today, but requires a not-yet shipped update to pe_patch
for Windows (this setting has no effect on Windows today)
Default value: false
use_pe_patch
Data type: Optional[Boolean]
Use the pe_patch module if available (PE 2019.8+). Defaults to true.
Default value: true
classify_pe_patch
Data type: Optional[Boolean]
Controls if the pe_patch class (PE 2019.8+) is controlled by this module. When enabled, this module will classify the node with pe_patch, and set it's patch_group according to this module's patch_group. When disabled (default), you can use PE's own "PE Patch Management" groups to classify nodes with pe_patch. In that case, please make sure you match the patch_group variable in pe_patch with the patch_group in patching_as_code
Default value: false
patch_on_metered_links
Data type: Optional[Boolean]
Controls if patches are installed when the active network connection is a metered link. This setting only has affect for Windows operating systems. When enabled, patching are installed even over a metered link. When disabled (default), patches are not installed over a metered link.
Default value: false
What are tasks?
Modules can contain tasks that take action outside of a desired state managed by Puppet. It’s perfect for troubleshooting or deploying one-off changes, distributing scripts to run across your infrastructure, or automating changes that need to happen in a particular order as part of an application deployment.
Tasks in this module release
Changelog
All notable changes to this project will be documented in this file.
Release 0.6.2
Features
- Adds support for setting the value
Any
to theday_of_week
parameter in a patch schedule
Release 0.6.1
Bugfixes
- Removed the
weekday
attribute of theschedule
resource that this module uses internally to restrict when patches can be applied. In certain edge cases where the Puppet server is in a very different timezone from a managed node, there can be a 1 day date difference between the two systems. This creates a scenario where the node never receives a valid patch schedule. By removing theweekday
parameter from theschedule
resource, this can no longer occur. Other logic still protects the actual day on which the patching is allowed so this parameter wasn't necessary.
Release 0.6.0
Features
- Adds support for providing an array of values to the
patch_group
attribute of thepatching_as_code
class - Adds support for providing an array of values to the
count_of_week
parameter in a patch schedule
Release 0.5.0
Features
- Removes dependency on the
windows_updates
module, we can now install Windows Updates natively - Adds a Task to install a Windows Update over WinRM or PCP
- Updates the PDK to 2.0.0
- No longer fails the resource if the Windows Update is no longer available/applicable for the node
- Write a
patching_as_code_config
fact that reports configuration state - Support security-only patching via a new
security_only
parameter to the class. This works for Linux today, but requires a not-yet shipped update tope_patch
for Windows - Preparations for being able to run
patching_as_code
as a plan, not yet active.
Release 0.4.3
Bugfixes
- Ensure
yum-utils
package on all RedHat/CentOS versions, not just 8 - Use
ensure_packages()
for safer enforcement ofyum-utils
package
Release 0.4.2
Bugfixes
- Account for
$facts['operatingsystemmajrelease']
returning a string instead of an integer
Release 0.4.1
Bugfixes
- For parsing the result of
/usr/bin/needs-restarting -r
in CentOS 7/8, the script wasif [ $? -eq 0 ]
instead ofif [ $? -eq 1 ]
, which caused the logic to be flipped.
Release 0.4.0
Features
- Completely rewrote the reboot behavior, so that pending reboot detections fully works both before patching and after patching, in the same Puppet run. There is no more dependency on the
reboots.reboot_required
portion of thepe_patch
/os_patching
fact, all logic is now internal and no longer requires multiple Puppet runs. - Changed the default schedules to
reboot: ifneeded
(wasreboot: always
), now that the pending reboot logic has improved so much - Ensured that pre_reboot commands will now trigger when necessary (only one scenario can happen at a time):
- when an OS pending reboot is detected at the start of a run (before patching)
- when an OS pending reboot is detected at the end of a run (after patching)
- Forced pre_reboot commands (which are essentially Exec resources) to use the
posix
provider on Linux and thepowershell
provider on Windows, so that the pending reboot detection logic can be injected to the resource dynamically.
Release 0.3.0
Features
- Rewrote updating of Linux packages to use a custom type (
patch_package
), which dynamically updates and/or createspackage
resources for patching in the catalog on the agent side. This ensures no duplicate package declarations can occur on the server side, due to the parsing-order dependency ofdefined()
anddefined_with_params()
. Neither of these functions are used anymore.
Release 0.2.9
Bugfixes
- Also protect against duplicate package declarations when
ensure
is set to a version. This isn't 100% bulletproof as the check is parse-order-dependent, but will work in most cases.
Release 0.2.8
Bugfixes
- Ensured Linux patches cannot cause duplicate declarations
Release 0.2.7
Bugfixes
- Added dependency to
puppetlabs/puppet_agent
to the module's metadata
Release 0.2.6
Features
- Added a
patch_unsafe_process_active
custom fact that reflects if any process from theunsafe_process_list
parameter was found active on the system. - Added a
unsafe_process_list
parameter to thepatching_as_code
class, which defines processes for the system that must cause patching to be skipped if any of those processes are active. Defaults to an empty array.
Release 0.2.5
Features
- Added cache cleanup for other providers (dnf, apt, zypper)
- Added refresh of
pe_patch::fact::exec
/os_patching::fact::exec
resources, to auto-update patch state after patching. This prevents unneccesary patching runs that perform no updates
Bugfixes
- Increased reboot delay after patching from 1 to 5 minutes, to account for remaining activities in the Puppet run
Release 0.2.4
Bugfixes
- Fixes the datatype of the
metered_link
fact, this was expected to be Boolean but got reported as a String, causing the logic to break.
Release 0.2.3
Features
- Added a
metered_link
custom fact that detects metered network connections on Windows - Added a
patch_on_metered_links
parameter to thepatching_as_code
class, which controls if patches are installed when running over a metered link (Windows only). Defaults tofalse
.
Release 0.2.2
Features
- This update ensures that patching_as_code defaults to NOT classify the pe_patch class on PE 2019.8.0, so that you can use the builtin "PE Patch Management" node group(s) to classify pe_patch. Since UI will be further improved in PE for this, it makes sense that this would be the leading way to classify pe_patch. This module can still be given control over pe_patch, as described in the updated Readme.
- The blacklist and whitelist have been renamed to blocklist and allowlist.
- Documentation has been updated, with a reference for the main manifest.
Release 0.2.1
Bugfixes Ensure pre/post-patching & pre-reboot commands use the same schedule
Release 0.2.0
Fixes pending reboot logic, adds pre/post-patching & pre-reboot command support
Features
- Ensures pending reboots are handled correctly, skipping patch installs completely
- Allows defining
Exec
resources dynamically for pre/post-patching & pre-reboot commands - Refactors reboot logic into main manifest
Known Issues Tested on Windows 2016 and 2019, and CentOS 7
Release 0.1.0
Initial release
Features
- Integrates with
albatrossflavour/os_patching
andpuppetlabs/pe_patch
- Customizable patch windows
- Patch window based on Nth weekday in the month
- Reboot control
- Yum clean support
Known Issues Tested on Windows 2016 and 2019, and CentOS 7
Dependencies
- puppetlabs/powershell (>= 3.0.1 < 5.0.0)
- puppetlabs/pwshlib (>= 0.4.1 < 2.0.0)
- puppetlabs/puppet_agent (>= 4.0.0 < 6.0.0)
- puppetlabs/reboot (>= 2.4.0 < 4.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.