├── README ├── aws_ec2_assign_elastic_ip ├── settings.conf ├── logging.conf ├── command_line_options.py └── __init__.py ├── requirements.txt ├── MANIFEST.in ├── Makefile ├── .gitignore ├── aws-ec2-assign-elastic-ip ├── setup.py ├── cf-template.json ├── README.md └── LICENSE /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /aws_ec2_assign_elastic_ip/settings.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | version: 0.10.2 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | boto3>=1.0.0 2 | ec2-metadata>=1.8.0 3 | netaddr>=0.7.12 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include aws_ec2_assign_elastic_ip * 2 | include aws-ec2-assign-elastic-ip 3 | include README 4 | include LICENSE 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | release: 2 | python setup.py sdist 3 | python3 -m twine upload --repository-url https://upload.pypi.org/legacy/ dist/* 4 | rm dist/* 5 | -------------------------------------------------------------------------------- /aws_ec2_assign_elastic_ip/logging.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root 3 | 4 | [logger_root] 5 | handlers=screen 6 | level=NOTSET 7 | 8 | [formatters] 9 | keys=simple 10 | 11 | [formatter_simple] 12 | format=%(asctime)s - aws-ec2-assign-eip - %(levelname)s - %(message)s 13 | 14 | [handlers] 15 | keys=screen 16 | 17 | [handler_screen] 18 | class=StreamHandler 19 | formatter=simple 20 | level=INFO 21 | args=(sys.stdout,) 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | -------------------------------------------------------------------------------- /aws-ec2-assign-elastic-ip: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ AWS EC2 Assign Elastic IP 3 | 4 | Automatically assign Elastic IPs to AWS EC2 instances. This can be really nice 5 | in auto scaling groups were you need to communicate the external IP's to 6 | third party systems. 7 | 8 | APACHE LICENSE 2.0 9 | 10 | Copyright 2014 Skymill Solutions 11 | 12 | Licensed under the Apache License, Version 2.0 (the "License"); 13 | you may not use this file except in compliance with the License. 14 | You may obtain a copy of the License at 15 | 16 | http://www.apache.org/licenses/LICENSE-2.0 17 | 18 | Unless required by applicable law or agreed to in writing, software 19 | distributed under the License is distributed on an "AS IS" BASIS, 20 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | See the License for the specific language governing permissions and 22 | limitations under the License. 23 | """ 24 | import sys 25 | 26 | import aws_ec2_assign_elastic_ip 27 | 28 | 29 | if __name__ == '__main__': 30 | try: 31 | aws_ec2_assign_elastic_ip.main() 32 | except KeyboardInterrupt: 33 | sys.exit(0) 34 | sys.exit(0) 35 | 36 | sys.exit(1) 37 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """ Setup script for PyPI """ 2 | import os 3 | from setuptools import setup 4 | try: 5 | from ConfigParser import SafeConfigParser 6 | except ImportError: 7 | from configparser import SafeConfigParser 8 | 9 | settings = SafeConfigParser() 10 | settings.read(os.path.realpath('aws_ec2_assign_elastic_ip/settings.conf')) 11 | 12 | setup( 13 | name='aws-ec2-assign-elastic-ip', 14 | version=settings.get('general', 'version'), 15 | license='Apache License, Version 2.0', 16 | description='Automatically assign Elastic IPs to AWS EC2 instances', 17 | author='Sebastian Dahlgren, Skymill Solutions', 18 | author_email='sebastian.dahlgren@skymill.se', 19 | url='https://github.com/skymill/aws-ec2-assign-elastic-ip', 20 | keywords="aws amazon web services ec2 as elasticip eip", 21 | platforms=['Any'], 22 | packages=['aws_ec2_assign_elastic_ip'], 23 | scripts=['aws-ec2-assign-elastic-ip'], 24 | include_package_data=True, 25 | zip_safe=False, 26 | install_requires=['boto3 >= 1.0.0', 'netaddr >= 0.7.12', 'ec2-metadata >= 1.8.0'], 27 | classifiers=[ 28 | 'Development Status :: 4 - Beta', 29 | 'Environment :: Console', 30 | 'License :: OSI Approved :: Apache Software License', 31 | 'Operating System :: OS Independent', 32 | 'Programming Language :: Python' 33 | ] 34 | ) 35 | -------------------------------------------------------------------------------- /aws_ec2_assign_elastic_ip/command_line_options.py: -------------------------------------------------------------------------------- 1 | """ Command line parser """ 2 | import argparse 3 | import sys 4 | try: 5 | from ConfigParser import SafeConfigParser 6 | except ImportError: 7 | from configparser import SafeConfigParser 8 | from argparse import RawTextHelpFormatter 9 | 10 | if sys.platform in ['win32', 'cygwin']: 11 | import ntpath as ospath 12 | else: 13 | import os.path as ospath 14 | 15 | SETTINGS = SafeConfigParser() 16 | SETTINGS.read('{0}/settings.conf'.format( 17 | ospath.dirname(ospath.realpath(__file__)))) 18 | 19 | PARSER = argparse.ArgumentParser( 20 | description='Assign EC2 Elastic IP to the current instance', 21 | formatter_class=RawTextHelpFormatter) 22 | PARSER.add_argument( 23 | '--version', 24 | action='count', 25 | help='Print the aws-ec2-assign-elastic-ip version and exit') 26 | PARSER.add_argument( 27 | '--region', 28 | default='us-east-1', 29 | help='AWS region. Default: us-east-1') 30 | PARSER.add_argument( 31 | '--access-key', 32 | help='AWS access key ID') 33 | PARSER.add_argument( 34 | '--secret-key', 35 | help='AWS secret access key ID') 36 | PARSER.add_argument( 37 | '--dry-run', 38 | action='store_true', 39 | help=( 40 | 'Turn on dry run mode. No address will be assigned,\n' 41 | 'we will only print which we whould take')) 42 | PARSER.add_argument( 43 | '--valid-ips', 44 | help=( 45 | 'A comma separated list of valid Elastic IPs.\nYou can use CIDR ' 46 | 'expressions to select ranges.\nValid examples:\n' 47 | '- 58.0.0.0/8\n' 48 | '- 123.213.0.0/16,58.0.0.0/8,195.234.023.0\n' 49 | '- 195.234.234.23,195.234.234.24\n')) 50 | PARSER.add_argument( 51 | '--invalid-ips', 52 | help=( 53 | 'A comma separated list of Elastic IP ranges that should not ' 54 | 'be used for assigning an ip. \n You can use CIDR ' 55 | 'expressions to select ranges.\nValid examples:\n' 56 | '- 58.0.0.0/8\n' 57 | '- 123.213.0.0/16,58.0.0.0/8,195.234.023.0\n' 58 | '- 195.234.234.23,195.234.234.24\n')) 59 | ARGS = PARSER.parse_args() 60 | 61 | if ARGS.version: 62 | print('AWS EC2 Assign Elastic IP: {0}'.format( 63 | SETTINGS.get('general', 'version'))) 64 | sys.exit(0) 65 | -------------------------------------------------------------------------------- /cf-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "Description" : "Test of Elastic IP association", 3 | 4 | "AWSTemplateFormatVersion" : "2010-09-09", 5 | 6 | "Parameters" : { 7 | 8 | "InstanceType" : { 9 | "Description" : "EC2 instance type for backup server", 10 | "Type" : "String", 11 | "Default" : "t2.micro" 12 | }, 13 | 14 | "KeyName" : { 15 | "Description" : "Key pair name", 16 | "Type" : "String" 17 | } 18 | 19 | }, 20 | 21 | "Mappings" : { 22 | 23 | "AWSInstanceType2Arch" : { 24 | "t1.micro": { "Arch" : "64" } 25 | }, 26 | 27 | "AWSRegionArch2AMI": { 28 | "eu-west-1": { 29 | "32" : "NOT_YET_SUPPORTED", 30 | "64" : "ami-76817c1e", 31 | "64HVM" : "NOT_YET_SUPPORTED" 32 | } 33 | } 34 | }, 35 | 36 | "Resources" : { 37 | "LaunchConfiguration" : { 38 | "Type": "AWS::AutoScaling::LaunchConfiguration", 39 | 40 | "Properties": { 41 | "ImageId" : { 42 | "Fn::FindInMap" : [ 43 | "AWSRegionArch2AMI", 44 | { "Ref" : "AWS::Region" }, 45 | { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } 46 | ] 47 | }, 48 | "AssociatePublicIpAddress" : true, 49 | "InstanceType" : { "Ref" : "InstanceType" }, 50 | "SecurityGroups" : [ { "Ref" : "SecurityGroup" } ], 51 | "KeyName" : { "Ref" : "KeyName" }, 52 | "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ 53 | "#!/bin/bash -v\n", 54 | 55 | "# Install cfn bootstraping tools\n", 56 | "apt-get update\n", 57 | "apt-get -y install python-setuptools python-pip\n", 58 | "easy_install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n", 59 | 60 | "# Make sure we have the latest aws-ec2-assign-elastic-ip\n", 61 | "pip install aws-ec2-assign-elastic-ip==0.1.0b1 || error_exit 'Failed upgrading aws-ec2-assign-elastic-ip to the latest version'\n", 62 | 63 | "# Assign an Elastic IP\n", 64 | "aws-ec2-assign-elastic-ip", 65 | " --access-key ", { "Ref" : "AccessKeys" }, 66 | " --secret-key ", { "Fn::GetAtt": ["AccessKeys", "SecretAccessKey"] }, 67 | " --region ", { "Ref" : "AWS::Region" }, 68 | " >> /var/log/aws-ec2-assign-elastic-ip.log\n" 69 | ]]}} 70 | } 71 | }, 72 | 73 | "AutoScalingGroup": { 74 | "Type": "AWS::AutoScaling::AutoScalingGroup", 75 | "Properties": { 76 | "LaunchConfigurationName": { "Ref": "LaunchConfiguration" }, 77 | "MinSize": "1", 78 | "MaxSize": "1", 79 | "Tags" : [ 80 | { 81 | "Key" : "Name", 82 | "Value" : { "Ref" : "AWS::StackName" }, 83 | "PropagateAtLaunch" : true 84 | } 85 | ] 86 | } 87 | }, 88 | 89 | "User" : { 90 | "Type" : "AWS::IAM::User", 91 | "Properties" : { 92 | "Path": "/", 93 | "Policies": [ 94 | { 95 | "PolicyName": "cloudformation", 96 | "PolicyDocument": { "Statement":[{ 97 | "Effect":"Allow", 98 | "Action":[ 99 | "cloudformation:DescribeStackResource", 100 | "ec2:*" 101 | ], 102 | "Resource":"*" 103 | }]} 104 | } 105 | ] 106 | } 107 | }, 108 | 109 | "AccessKeys" : { 110 | "Type" : "AWS::IAM::AccessKey", 111 | "Properties" : { 112 | "UserName" : {"Ref": "User"} 113 | } 114 | }, 115 | 116 | "EIP1" : { "Type" : "AWS::EC2::EIP" }, 117 | "EIP2" : { "Type" : "AWS::EC2::EIP" }, 118 | "EIP3" : { "Type" : "AWS::EC2::EIP" }, 119 | 120 | "SecurityGroup" : { 121 | "Type": "AWS::EC2::SecurityGroup", 122 | "Properties" : { 123 | "GroupDescription": "Security group", 124 | "SecurityGroupIngress": [ 125 | { "IpProtocol": "tcp", "FromPort": "22", "ToPort": "22", "CidrIp": "0.0.0.0/0" } 126 | ], 127 | "Tags" : [ 128 | { "Key": "Name", "Value" : { "Ref" : "AWS::StackName" } } 129 | ] 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | aws-ec2-assign-elastic-ip 2 | ========================= 3 | 4 |

5 | 6 | 7 |

8 | 9 | Automatically assign Elastic IPs to AWS EC2 instances. This can be really nice 10 | in auto scaling groups were you need to communicate the external IP's to third 11 | party systems. 12 | 13 | The script should be executed on the EC2 instance that should get assigned an 14 | Elastic IP. This is typically done as part of the instance boot process. 15 | 16 | `aws-ec2-assign-elastic-ip` is idempotent and will not assign an new Elastic IP 17 | if the instance already has one. 18 | 19 | Installation 20 | ------------ 21 | 22 | `aws-ec2-assign-elastic-ip` is easiest to install via PyPI. 23 | 24 | pip install aws-ec2-assign-elastic-ip 25 | 26 | Configuration options 27 | --------------------- 28 | 29 | The script is configured using command line options. You can provide your AWS 30 | credentials directly on the command line, but the script also supports all [boto 31 | credential config options](http://boto.readthedocs.org/en/latest/boto_config_tut.html#credentials) 32 | and AWS instance profiles. 33 | 34 | usage: aws-ec2-assign-elastic-ip [-h] [--version] [--region REGION] 35 | [--access-key ACCESS_KEY] 36 | [--secret-key SECRET_KEY] [--dry-run] 37 | [--valid-ips VALID_IPS] 38 | 39 | Assign EC2 Elastic IP to the current instance 40 | 41 | optional arguments: 42 | -h, --help show this help message and exit 43 | --version Print the Automated EBS Snapshots version and exit 44 | --region REGION AWS region. Default: us-east-1 45 | --access-key ACCESS_KEY 46 | AWS access key ID 47 | --secret-key SECRET_KEY 48 | AWS secret access key ID 49 | --dry-run Turn on dry run mode. No address will be assigned, 50 | we will only print which we whould take 51 | --valid-ips VALID_IPS 52 | A comma separated list of valid Elastic IPs. 53 | You can use CIDR expressions to select ranges. 54 | Valid examples: 55 | - 58.0.0.0/8 56 | - 123.213.0.0/16,58.0.0.0/8,195.234.023.0 57 | - 195.234.234.23,195.234.234.24 58 | --invalid-ips INVALID_IPS 59 | A comma separated list of Elastic IP ranges that 60 | should NOT be used for assigning an ip. 61 | You can use CIDR expressions to select ranges. 62 | Valid examples: 63 | - 58.0.0.0/8 64 | - 123.213.0.0/16,58.0.0.0/8,195.234.023.0 65 | - 195.234.234.23,195.234.234.24 66 | 67 | 68 | The `--valid-ips` and `--invalid-ips` options require the public IPs in a comma separated sequence. 69 | E.g. `56.123.56.123,56.123.56.124,56.123.56.125`. 70 | 71 | Supported platforms 72 | ------------------- 73 | 74 | The `aws-ec2-assign-elastic-ip` should work fine on Linux, Mac OS X and 75 | Microsoft Windows. Please submit an issue if you have any issues with any of the 76 | platforms. 77 | 78 | We currently support Python 2.6, 2.7 and 3.X 79 | 80 | Required IAM permissions 81 | ------------------------ 82 | 83 | We have been using the following IAM policies to be able to list and associate Elastic IPs. It allows EC2 `ec2:DescribeAddresses` and `ec2:AssociateAddress` permissions: 84 | 85 | { 86 | "Statement": [ 87 | { 88 | "Effect": "Allow", 89 | "Action": [ 90 | "ec2:AssociateAddress", 91 | "ec2:DescribeAddresses" 92 | ], 93 | "Resource": "*" 94 | } 95 | ] 96 | } 97 | 98 | License 99 | ------- 100 | 101 | APACHE LICENSE 2.0 102 | 103 | Copyright 2014 Skymill Solutions 104 | 105 | Licensed under the Apache License, Version 2.0 (the "License"); 106 | you may not use this file except in compliance with the License. 107 | You may obtain a copy of the License at 108 | 109 | http://www.apache.org/licenses/LICENSE-2.0 110 | 111 | Unless required by applicable law or agreed to in writing, software 112 | distributed under the License is distributed on an "AS IS" BASIS, 113 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 114 | See the License for the specific language governing permissions and 115 | limitations under the License. 116 | -------------------------------------------------------------------------------- /aws_ec2_assign_elastic_ip/__init__.py: -------------------------------------------------------------------------------- 1 | """ Assign EC2 Elastic IP to the current instance """ 2 | import logging 3 | import logging.config 4 | import sys 5 | import random 6 | 7 | if sys.platform in ['win32', 'cygwin']: 8 | import ntpath as ospath 9 | else: 10 | import os.path as ospath 11 | 12 | from netaddr import IPNetwork, AddrFormatError, AddrConversionError 13 | 14 | from ec2_metadata import ec2_metadata 15 | import boto3 16 | 17 | from aws_ec2_assign_elastic_ip.command_line_options import ARGS as args 18 | 19 | 20 | logging.config.fileConfig('{0}/logging.conf'.format( 21 | ospath.dirname(ospath.realpath(__file__)))) 22 | 23 | logger = logging.getLogger('aws-ec2-assign-eip') 24 | 25 | region = args.region 26 | 27 | try: 28 | region = ec2_metadata.region 29 | except KeyError: 30 | pass 31 | 32 | # Connect to AWS EC2 33 | if args.access_key or args.secret_key: 34 | # Use command line credentials 35 | connection = boto3.client('ec2', 36 | region_name=region, 37 | aws_access_key_id=args.access_key, 38 | aws_secret_access_key=args.secret_key) 39 | else: 40 | # Use environment vars or global boto configuration or instance metadata 41 | connection = boto3.client('ec2', 42 | region_name=region) 43 | logger.info('Connected to AWS EC2 in {0}'.format(region)) 44 | 45 | 46 | def main(): 47 | """ Main function """ 48 | # Get our instance name 49 | instance_id = ec2_metadata.instance_id 50 | 51 | # Check if the instance already has an Elastic IP 52 | # If so, exit 53 | if _has_associated_address(instance_id): 54 | logger.warning('{0} is already assigned an Elastic IP. Exiting.'.format( 55 | instance_id)) 56 | sys.exit(0) 57 | 58 | # Get an unassigned Elastic IP 59 | address = _get_unassociated_address() 60 | 61 | # Exit if there were no available Elastic IPs 62 | if not address: 63 | sys.exit(1) 64 | 65 | # Assign the Elastic IP to our instance 66 | if args.dry_run: 67 | logger.info('Would assign IP {0}'.format(address['PublicIp'])) 68 | else: 69 | _assign_address(instance_id, address) 70 | 71 | 72 | def _assign_address(instance_id, address): 73 | """ Assign an address to the given instance ID 74 | 75 | :type instance_id: str 76 | :param instance_id: Instance ID 77 | :type address: boto.ec2.address 78 | :param address: Elastic IP address 79 | :returns: None 80 | """ 81 | logger.debug('Trying to associate {0} with {1}'.format( 82 | instance_id, address['PublicIp'])) 83 | 84 | # Check if this is an VPC or standard allocation 85 | try: 86 | if address['Domain'] == 'standard': 87 | # EC2 classic association 88 | connection.associate_address( 89 | InstanceId=instance_id, 90 | PublicIp=address['PublicIp'], 91 | AllowReassociation=False) 92 | else: 93 | # EC2 VPC association 94 | connection.associate_address( 95 | InstanceId=instance_id, 96 | AllocationId=address['AllocationId'], 97 | AllowReassociation=False) 98 | except Exception as error: 99 | logger.error('Failed to associate {0} with {1}. Reason: {2}'.format( 100 | instance_id, address['PublicIp'], error)) 101 | sys.exit(1) 102 | 103 | logger.info('Successfully associated Elastic IP {0} with {1}'.format( 104 | address['PublicIp'], instance_id)) 105 | 106 | 107 | def _get_unassociated_address(): 108 | """ Return the first unassociated EIP we can find 109 | Shuffles list before iterating to alleviate collisions 110 | 111 | :returns: boto.ec2.address or None 112 | """ 113 | eip = None 114 | 115 | try: 116 | all_addresses = connection.describe_addresses()['Addresses'] 117 | except KeyError as error: 118 | logger.error('Address list could not be read: "{0}"'.format(error)) 119 | return eip 120 | 121 | random.shuffle(all_addresses) 122 | for address in all_addresses: 123 | # Check if the address is associated 124 | if 'InstanceId' in address.keys(): 125 | logger.debug('{0} is already associated with {1}'.format( 126 | address['PublicIp'], address['InstanceId'])) 127 | continue 128 | 129 | # Check if the address is attached to an ENI 130 | if 'NetworkInterfaceId' in address.keys(): 131 | logger.debug('{0} is already attached to {1}'.format( 132 | address['PublicIp'], address['NetworkInterfaceId'])) 133 | continue 134 | 135 | # Check if the address is in the valid IP's list 136 | if _is_valid(address['PublicIp']): 137 | logger.debug('{0} is unassociated and OK for us to take'.format( 138 | address['PublicIp'])) 139 | eip = address 140 | break 141 | 142 | else: 143 | logger.debug( 144 | '{0} is unassociated, but not in the valid IPs list'.format( 145 | address['PublicIp'])) 146 | 147 | if not eip: 148 | logger.error('No unassociated Elastic IP found!') 149 | 150 | return eip 151 | 152 | 153 | def _has_associated_address(instance_id): 154 | """ Check if the instance has an Elastic IP association 155 | 156 | :type instance_id: str 157 | :param instance_id: Instances ID 158 | :returns: bool -- True if the instance has an Elastic IP associated 159 | """ 160 | if connection.describe_addresses(Filters=[{'Name': 'instance-id', 'Values': [ec2_metadata.instance_id]}])['Addresses']: 161 | return True 162 | return False 163 | 164 | def _is_ip_in_range(address, ips): 165 | """ Check if the IP is in a given range. 166 | 167 | :type address: str 168 | :param address: IP address to check 169 | :type ips: str 170 | :param ips: IP range 171 | :returns: bool -- True if association is OK 172 | """ 173 | if not ips: 174 | return True 175 | 176 | for conf_ip in ips.split(','): 177 | try: 178 | for ip in IPNetwork(conf_ip): 179 | if str(ip) == str(address): 180 | return True 181 | 182 | except AddrFormatError as err: 183 | logger.error('Invalid valid IP configured: {0}'.format(err)) 184 | pass 185 | 186 | except AddrConversionError as err: 187 | logger.error('Invalid valid IP configured: {0}'.format(err)) 188 | pass 189 | 190 | return False 191 | 192 | 193 | def _is_valid(address): 194 | """ Check if the configuration allows us to assign this address 195 | 196 | :type address: str 197 | :param address: IP address to check 198 | :returns: bool -- True if association is OK 199 | """ 200 | if _is_ip_in_range(address, args.valid_ips): 201 | if args.invalid_ips and _is_ip_in_range(address, args.invalid_ips): 202 | return False 203 | else: 204 | return True 205 | 206 | return False 207 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. --------------------------------------------------------------------------------