ebcli/objects/requests.py (374 lines of code) (raw):
# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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.
import copy
from ebcli.objects.solutionstack import SolutionStack
from ebcli.objects.platform import PlatformVersion
from ebcli.resources.strings import strings
from ebcli.resources.statics import elb_names, namespaces, option_names
class OptionSetting(object):
def __init__(self, namespace, option_name, value):
self.namespace = namespace
self.option_name = option_name
self.value = value
def __eq__(self, other):
return self.__hash__() == other.__hash__()
def __hash__(self):
"""
__hash__ method for `OptionSetting` to enable comparison of sets of `OptionSetting`s objects.
:return: a hash of the `tuple` of the `OptionSetting` attributes
"""
return hash((self.namespace, self.option_name, self.value))
@classmethod
def option_settings_from_json(cls, json_array):
option_settings = set()
for option_setting in json_array:
option_settings.add(
OptionSetting(
namespace=option_setting['Namespace'],
option_name=option_setting['OptionName'],
value=option_setting['Value'],
)
)
return option_settings
class CreateEnvironmentRequest(object):
def __init__(self, app_name=None, env_name=None, cname=None, platform=None,
tier=None, instance_type=None, version_label=None,
instance_profile=None, service_role=None,
single_instance=False, key_name=None,
sample_application=False, tags=None, scale=None,
database=None, vpc=None, template_name=None, group_name=None,
elb_type=None, shared_lb=None, shared_lb_port=None, enable_spot=None, instance_types=None,
spot_max_price=None, on_demand_base_capacity=None,
on_demand_above_base_capacity=None, min_instances=None,
max_instances=None, block_device_mappings=None, listener_configs=None,
description=None, load_balancer_security_group=None, ec2_security_group=None,
ssl_certificate=None, root_volume=None):
self.app_name = app_name
self.cname = cname
self.env_name = env_name
self.instance_profile = instance_profile
self.instance_type = instance_type
self.key_name = key_name
self.platform = platform
self.sample_application = sample_application
self.service_role = service_role
self.single_instance = single_instance
self.template_name = template_name
self.tier = tier
self.version_label = version_label
self.group_name = group_name
if tags is None:
self.tags = []
else:
self.tags = list(tags)
if database is None:
self.database = {}
else:
self.database = dict(database)
if vpc is None:
self.vpc = {}
else:
self.vpc = dict(vpc)
self.elb_type = elb_type
self.shared_lb = shared_lb
self.shared_lb_port = shared_lb_port
self.scale = None
self.option_settings = []
self.compiled = False
self.description = description or strings['env.description']
self.enable_spot = enable_spot
self.instance_types = instance_types
self.spot_max_price = spot_max_price
self.on_demand_base_capacity = on_demand_base_capacity
self.on_demand_above_base_capacity = on_demand_above_base_capacity
self.min_instances = min_instances
self.max_instances = max_instances
self.block_device_mappings = block_device_mappings
self.ssl_certificate = ssl_certificate
if listener_configs:
self.merge_option_settings(listener_configs)
if load_balancer_security_group:
self.merge_option_settings([load_balancer_security_group])
if ec2_security_group:
security_groups_expressed_through_vpc_config = self.vpc and self.vpc.get('securitygroups')
if not security_groups_expressed_through_vpc_config :
self.merge_option_settings([ec2_security_group])
if not self.app_name:
raise TypeError(self.__class__.__name__ + ' requires key-word argument app_name')
if not self.env_name:
raise TypeError(self.__class__.__name__ + ' requires key-word argument env_name')
if scale:
if not isinstance(scale, int):
raise TypeError('key-word argument scale must be of type int')
else:
self.scale = str(scale)
if ssl_certificate:
self.add_option_setting(
namespaces.LOAD_BALANCER_V2,
option_names.SSL_CERT_ID,
ssl_certificate)
if root_volume:
self.merge_option_settings(root_volume)
def __eq__(self, other):
self_dict = copy.deepcopy(self.__dict__)
other_dict = copy.deepcopy(other.__dict__)
self_dict['option_settings'] = OptionSetting.option_settings_from_json(
self_dict.get('option_settings', [])
)
other_dict['option_settings'] = OptionSetting.option_settings_from_json(
other_dict.get('option_settings', [])
)
return self_dict == other_dict
def __ne__(self, other):
return not self == other
def add_option_setting(self, namespace, option_name, value, resource=None):
setting = {'Namespace': namespace,
'OptionName': option_name,
'Value': value}
if resource:
setting['ResourceName'] = resource
self.option_settings.append(setting)
def merge_option_settings(self, option_settings):
if not option_settings:
return
self.option_settings = self.option_settings or []
self.option_settings += option_settings
def convert_to_kwargs(self):
self.compile_option_settings()
return self.get_standard_kwargs()
def compile_option_settings(self):
if not self.compiled:
self.add_client_defaults()
self.compile_database_options()
self.compile_vpc_options()
self.compile_spot_options()
self.compile_common_options()
self.compile_shared_lb_options()
self.compiled = True
def get_standard_kwargs(self):
kwargs = {
'ApplicationName': self.app_name,
'EnvironmentName': self.env_name,
'OptionSettings': self.option_settings,
}
if self.platform:
if isinstance(self.platform, SolutionStack):
kwargs['SolutionStackName'] = self.platform.name
elif isinstance(self.platform, PlatformVersion):
kwargs['PlatformArn'] = self.platform.name
if self.description:
kwargs['Description'] = self.description
if self.cname:
kwargs['CNAMEPrefix'] = self.cname
if self.template_name:
kwargs['TemplateName'] = self.template_name
if self.version_label:
kwargs['VersionLabel'] = self.version_label
if self.tags:
kwargs['Tags'] = self.tags
if self.tier:
kwargs['Tier'] = self.tier.to_dict()
if self.scale:
self.add_option_setting(
namespaces.AUTOSCALING,
option_names.MAX_SIZE,
self.scale)
self.add_option_setting(
namespaces.AUTOSCALING,
option_names.MIN_SIZE,
self.scale)
return kwargs
def compile_common_options(self):
if self.instance_profile:
self.add_option_setting(
namespaces.LAUNCH_CONFIGURATION,
option_names.IAM_INSTANCE_PROFILE,
self.instance_profile)
if self.service_role:
self.add_option_setting(
namespaces.ENVIRONMENT,
option_names.SERVICE_ROLE,
self.service_role
)
if self.instance_type:
self.add_option_setting(
namespaces.LAUNCH_CONFIGURATION,
option_names.INSTANCE_TYPE,
self.instance_type)
if self.instance_types:
self.add_option_setting(
namespaces.SPOT,
option_names.INSTANCE_TYPES,
self.instance_types)
if self.single_instance:
self.add_option_setting(
namespaces.ENVIRONMENT,
option_names.ENVIRONMENT_TYPE,
'SingleInstance')
if self.key_name:
self.add_option_setting(
namespaces.LAUNCH_CONFIGURATION,
option_names.EC2_KEY_NAME,
self.key_name)
if self.scale:
self.add_option_setting(
namespaces.AUTOSCALING,
option_names.MAX_SIZE,
self.scale)
self.add_option_setting(
namespaces.AUTOSCALING,
option_names.MIN_SIZE,
self.scale)
if self.min_instances:
self.add_option_setting(
namespaces.AUTOSCALING,
option_names.MIN_SIZE,
self.min_instances)
if self.max_instances:
self.add_option_setting(
namespaces.AUTOSCALING,
option_names.MAX_SIZE,
self.max_instances)
if self.elb_type:
self.add_option_setting(
namespaces.ENVIRONMENT,
option_names.LOAD_BALANCER_TYPE,
self.elb_type)
if self.block_device_mappings:
self.add_option_setting(
namespaces.LAUNCH_CONFIGURATION,
option_names.BLOCK_DEVICE_MAPPINGS,
self.block_device_mappings
)
def add_client_defaults(self):
if self.template_name:
return
if self.platform and self.platform.has_healthd_support:
self.add_option_setting(
namespaces.HEALTH_SYSTEM,
option_names.SYSTEM_TYPE,
'enhanced')
self.add_option_setting(
namespaces.COMMAND,
option_names.BATCH_SIZE,
'30')
self.add_option_setting(
namespaces.COMMAND,
option_names.BATCH_SIZE_TYPE,
'Percentage')
if not self.tier or self.tier.name.lower() == 'webserver':
self.add_option_setting(
namespaces.ELB_POLICIES,
option_names.CONNECTION_DRAINING,
'true')
self.add_option_setting(
namespaces.LOAD_BALANCER,
option_names.CROSS_ZONE,
'true')
if not self.single_instance:
self.add_option_setting(
namespaces.ROLLING_UPDATES,
option_names.ROLLING_UPDATE_ENABLED,
'true')
self.add_option_setting(
namespaces.ROLLING_UPDATES,
option_names.ROLLING_UPDATE_TYPE,
'Health')
def compile_database_options(self):
if not self.database:
return
namespace = namespaces.RDS
self.add_option_setting(namespace, option_names.DB_PASSWORD,
self.database['password'])
self.add_option_setting(namespace, option_names.DB_USER,
self.database['username'])
if self.database['instance']:
self.add_option_setting(namespace, option_names.DB_INSTANCE,
self.database['instance'])
if self.database['size']:
self.add_option_setting(namespace, option_names.DB_STORAGE_SIZE,
self.database['size'])
if self.database['engine']:
self.add_option_setting(namespace, option_names.DB_ENGINE,
self.database['engine'])
if self.database['version']:
self.add_option_setting(namespace, option_names.DB_ENGINE_VERSION,
self.database['version'])
self.add_option_setting(namespace, option_names.DB_DELETION_POLICY,
'Snapshot')
def compile_vpc_options(self):
if not self.vpc:
return
namespace = namespaces.VPC
self.add_option_setting(namespace, option_names.VPC_ID,
self.vpc['id'])
if self.vpc.get('publicip'):
self.add_option_setting(
namespace,
option_names.PUBLIC_IP,
self.vpc['publicip']
)
if self.vpc.get('elbscheme'):
self.add_option_setting(namespace, option_names.ELB_SCHEME,
self.vpc['elbscheme'])
if self.vpc.get('elbsubnets'):
self.add_option_setting(namespace, option_names.ELB_SUBNETS,
self.vpc['elbsubnets'])
if self.vpc.get('ec2subnets'):
self.add_option_setting(namespace, option_names.SUBNETS,
self.vpc['ec2subnets'])
if self.vpc.get('securitygroups'):
self.add_option_setting(namespaces.LAUNCH_CONFIGURATION,
option_names.SECURITY_GROUPS,
self.vpc['securitygroups'])
if self.vpc.get('dbsubnets'):
self.add_option_setting(namespace, option_names.DB_SUBNETS,
self.vpc['dbsubnets'])
def compile_spot_options(self):
if not self.enable_spot:
return
namespace = namespaces.SPOT
self.add_option_setting(namespace, option_names.ENABLE_SPOT, 'true')
if self.on_demand_base_capacity:
self.add_option_setting(namespace, option_names.ON_DEMAND_BASE_CAPACITY, self.on_demand_base_capacity)
if self.on_demand_above_base_capacity:
self.add_option_setting(namespace, option_names.ON_DEMAND_PERCENTAGE_ABOVE_BASE_CAPACITY, self.on_demand_above_base_capacity)
if self.spot_max_price:
self.add_option_setting(namespace, option_names.SPOT_MAX_PRICE, self.spot_max_price)
if self.on_demand_base_capacity:
self.add_option_setting(namespace, option_names.ON_DEMAND_BASE_CAPACITY, self.on_demand_base_capacity)
if self.on_demand_above_base_capacity:
self.add_option_setting(
namespace,
option_names.ON_DEMAND_PERCENTAGE_ABOVE_BASE_CAPACITY,
self.on_demand_above_base_capacity)
def compile_shared_lb_options(self):
if self.elb_type != elb_names.APPLICATION_VERSION or self.shared_lb==None:
return
if self.shared_lb:
self.add_option_setting(
namespaces.ENVIRONMENT,
option_names.LOAD_BALANCER_IS_SHARED,
'true'
)
self.add_option_setting(
namespaces.LOAD_BALANCER_V2,
option_names.SHARED_LOAD_BALANCER,
self.shared_lb)
if self.shared_lb_port and self.shared_lb:
namespace = namespaces.LISTENER.format(self.shared_lb_port)
self.add_option_setting(
namespace,
option_names.LISTENER_RULE,
'default'
)
class CloneEnvironmentRequest(CreateEnvironmentRequest):
def __init__(self, app_name=None, env_name=None, original_name=None,
cname=None, platform=None, scale=None, tags=None):
if not original_name:
raise TypeError(self.__class__.__name__ + ' requires key-word argument clone_name')
self.original_name = original_name
super(CloneEnvironmentRequest, self).__init__(
app_name=app_name, env_name=env_name, cname=cname,
platform=platform, scale=scale, tags=tags
)
self.description = strings['env.clonedescription']. \
replace('{env-name}', self.env_name)
def compile_option_settings(self):
if not self.compiled:
self.compile_common_options()
self.compiled = True