Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions drivers/aws_shell/src/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,8 @@ def ApplyConnectivityChanges(self, context, ports, request):
def PrepareConnectivityChanges(self, context, request):
pass

def GetApplicationPorts(self, context, ports):
return self.aws_shell.get_application_ports(context)

def get_inventory(self, context):
pass
1 change: 1 addition & 0 deletions drivers/aws_shell/src/drivermetadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</Category>
<Category Name="Connectivity">
<Command Description="" DisplayName="Refresh IP" EnableCancellation="true" Name="remote_refresh_ip" Tags="remote_connectivity,allow_shared" />
<Command Description="" DisplayName="Get Application Ports" EnableCancellation="true" Name="GetApplicationPorts" Tags="remote_connectivity,allow_shared" />
<Command Description="" DisplayName="Apply Connectivity Changes" Name="ApplyConnectivityChanges" Tags="allow_unreserved" />
<Command Description="" DisplayName="Apply Connectivity Changes" Name="PrepareConnectivityChanges" Tags="allow_unreserved" />
</Category>
Expand Down
17 changes: 17 additions & 0 deletions package/cloudshell/cp/aws/aws_shell.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
from cloudshell.cp.aws.domain.ami_management.operations.delete_operation import DeleteAMIOperation
from cloudshell.cp.aws.domain.ami_management.operations.deploy_operation import DeployAMIOperation
from cloudshell.cp.aws.domain.ami_management.operations.power_operation import PowerOperation
from cloudshell.cp.aws.domain.deployed_app.operations.app_ports_operation import DeployedAppPortsOperation
from cloudshell.cp.aws.domain.services.ec2_services.aws_security_group_service import AWSSecurityGroupService
from cloudshell.cp.aws.domain.services.ec2_services.tag_creator_service import TagCreatorService
from cloudshell.cp.aws.domain.services.model_parser.aws_model_parser import AWSModelsParser
from cloudshell.cp.aws.domain.services.session_providers.aws_session_provider import AWSSessionProvider
from cloudshell.cp.aws.domain.services.storage_services.ec2_storage_service import EC2StorageService
from cloudshell.cp.aws.domain.services.task_manager.instance_waiter import EC2InstanceWaiter
from cloudshell.cp.aws.domain.services.model_parser.custom_param_extractor import VmCustomParamsExtractor


class AWSShell(object):
Expand All @@ -22,6 +24,7 @@ def __init__(self):
self.model_parser = AWSModelsParser()
self.cloudshell_session_helper = CloudshellDriverHelper()
self.aws_session_manager = AWSSessionProvider()
self.vm_custom_params_extractor = VmCustomParamsExtractor()

self.security_group_service = AWSSecurityGroupService()

Expand All @@ -37,6 +40,8 @@ def __init__(self):
ec2_storage_service=self.ec2_storage_service,
security_group_service=self.security_group_service)

self.deployed_app_ports_operation = DeployedAppPortsOperation(self.vm_custom_params_extractor)

def deploy_ami(self, command_context, deployment_request):
"""
Will deploy Amazon Image on the cloud provider
Expand Down Expand Up @@ -116,6 +121,18 @@ def delete_ami(self, command_context, delete_resource=True):

return self._set_command_result(result)

def get_application_ports(self, command_context):
"""
Will return the application ports in a nicely formated manner
:param command_context: RemoteCommandContext
:return:
"""
resource = command_context.remote_endpoints[0]
data_holder = self.model_parser.convert_app_resource_to_deployed_app(resource)

return self.deployed_app_ports_operation.get_formated_deployed_app_ports(data_holder.vmdetails.vmCustomParams)


@staticmethod
def _set_command_result(result, unpicklable=False):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from cloudshell.cp.aws.device_access_layer.aws_ec2 import AWSEC2Service
from cloudshell.cp.aws.domain.services.ec2_services.aws_security_group_service import AWSSecurityGroupService
from cloudshell.cp.aws.domain.services.ec2_services.tag_creator_service import TagCreatorService, IsolationTagValues
from cloudshell.cp.aws.domain.services.model_parser.port_group_attribute_parser import PortGroupAttributeParser
from cloudshell.cp.aws.models.deploy_result_model import DeployResult


Expand Down Expand Up @@ -68,6 +69,11 @@ def _create_security_group_for_instance(self, ami_deployment_model, aws_ec2_cp_r
if not ami_deployment_model.inbound_ports and not ami_deployment_model.outbound_ports:
return None

inbound_ports = PortGroupAttributeParser.parse_port_group_attribute(ami_deployment_model.inbound_ports)
outbound_ports = PortGroupAttributeParser.parse_port_group_attribute(ami_deployment_model.outbound_ports)
if not inbound_ports and not outbound_ports:
return None

security_group_name = AWSSecurityGroupService.QUALI_SECURITY_GROUP + " " + str(uuid.uuid4())

security_group = self.security_group_service.create_security_group(ec2_session,
Expand All @@ -80,7 +86,9 @@ def _create_security_group_for_instance(self, ami_deployment_model, aws_ec2_cp_r

self.aws_ec2_service.set_ec2_resource_tags(security_group, tags)

self.security_group_service.set_security_group_rules(ami_deployment_model, security_group)
self.security_group_service.set_security_group_rules(security_group=security_group,
inbound_ports=inbound_ports,
outbound_ports=outbound_ports)

return security_group

Expand Down
3 changes: 3 additions & 0 deletions package/cloudshell/cp/aws/domain/deployed_app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__author__ = 'quali'
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__author__ = 'quali'
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from cloudshell.cp.aws.domain.services.model_parser.port_group_attribute_parser import PortGroupAttributeParser
from cloudshell.cp.aws.models.port_data import PortData
from cloudshell.cp.aws.domain.services.model_parser.custom_param_extractor import VmCustomParamsExtractor


class DeployedAppPortsOperation(object):
def __init__(self, vm_custom_params_extractor):
"""
:param VmCustomParamsExtractor vm_custom_params_extractor:
:return:
"""
self.vm_custom_params_extractor = vm_custom_params_extractor

def get_formated_deployed_app_ports(self, custom_params):
"""
:param custom_params:
:return:
"""
inbound_ports_value = self.vm_custom_params_extractor.get_custom_param_value(custom_params, "inbound_ports")
outbound_ports_value = self.vm_custom_params_extractor.get_custom_param_value(custom_params, "outbound_ports")

if not inbound_ports_value and not outbound_ports_value:
return ""

result_str_list = []

if inbound_ports_value:
inbound_ports = PortGroupAttributeParser.parse_port_group_attribute(inbound_ports_value)
if inbound_ports:
result_str_list.append("Inbound ports:")
for rule in inbound_ports:
result_str_list.append(self._port_rule_to_string(rule))
result_str_list.append('')

if outbound_ports_value:
outbound_ports = PortGroupAttributeParser.parse_port_group_attribute(outbound_ports_value)
if outbound_ports:
result_str_list.append("Outbound ports:")
for rule in outbound_ports:
result_str_list.append(self._port_rule_to_string(rule))

return '\n'.join(result_str_list).strip()

def _port_rule_to_string(self, port_rule):
"""
:param PortData port_rule:
:return:
"""
if port_rule.from_port == port_rule.to_port:
port_str = port_rule.from_port
port_postfix = ""
else:
port_str = "{0}-{1}".format(port_rule.from_port, port_rule.to_port)
port_postfix = "s"

return "Port{0} {1} {2}".format(port_postfix, port_str, port_rule.protocol)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from cloudshell.cp.aws.domain.services.model_parser.port_group_attribute_parser import PortGroupAttributeParser
from cloudshell.cp.aws.models.port_data import PortData


class AWSSecurityGroupService(object):
Expand Down Expand Up @@ -28,15 +28,19 @@ def create_security_group(self, ec2_session, vpc, security_group_name):
Description=AWSSecurityGroupService.QUALI_SECURITY_GROUP_DESCRIPTION,
VpcId=vpc)

def set_security_group_rules(self, ami_deployment_model, security_group):
def set_security_group_rules(self, security_group, inbound_ports, outbound_ports):
"""
:param security_group: AWS SG object
:param list[PortData] inbound_ports:
:param list[PortData] outbound_ports:
:return:
"""
# adding inbound port rules
if ami_deployment_model.inbound_ports:
inbound_ports = PortGroupAttributeParser.parse_port_group_attribute(ami_deployment_model.inbound_ports)
if inbound_ports:
self._set_inbound_ports(inbound_ports, security_group)

# adding outbound port rules
if ami_deployment_model.outbound_ports:
outbound_ports = PortGroupAttributeParser.parse_port_group_attribute(ami_deployment_model.outbound_ports)
if outbound_ports:
self._set_outbound_ports(outbound_ports, security_group)

def _set_outbound_ports(self, outbound_ports, security_group):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class VmCustomParamsExtractor(object):
def __init__(self):
pass

def get_custom_param_value(self, custom_params, name):
"""
Returns the value of the requested custom param
:param custom_params: The VMCustomParams array that is created by the DeployDataHolder from the deployed app json
:param str name: the name of the custom param to extract
:return: the value of the custom param or None if custom param not found
:rtype str:
"""
name = name.lower()
params = filter(lambda x: x.name.lower() == name, custom_params)
if len(params) == 1:
return params[0].value
return None
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ class PortGroupAttributeParser(object):

@staticmethod
def parse_port_group_attribute(ports_attribute):

"""
:param ports_attribute:
:return:
:rtype: list[PortData]
"""
if ports_attribute:
splitted_ports = ports_attribute.split(';')
splitted_ports = filter(lambda x: x, ports_attribute.strip().split(';'))
port_data_array = [PortGroupAttributeParser._single_port_parse(port.strip()) for port in splitted_ports]
return port_data_array
return None
Expand All @@ -22,8 +26,6 @@ def _single_port_parse(ports_attribute):
protocol = 'protocol'
tcp = 'tcp'

port_data = None

from_to_protocol_match = re.match(r"^((?P<from_port>\d+)-(?P<to_port>\d+):(?P<protocol>(udp|tcp)))$",
ports_attribute)

Expand Down Expand Up @@ -61,4 +63,4 @@ def _single_port_parse(ports_attribute):
protocol = tcp
return PortData(from_port, to_port, protocol, destination)

return port_data
raise ValueError("The value '{0}' is not a valid ports rule".format(ports_attribute))
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,22 @@ def setUp(self):
self.ec2_datamodel.default_storage_size = 1
self.ec2_session = Mock()
self.ec2_serv = Mock()
self.security_group_man = Mock()
self.tag_creator = Mock()
self.deploy_operation = DeployAMIOperation(self.ec2_serv, self.security_group_man, self.tag_creator)
self.security_group_service = Mock()
self.tag_creator_service = Mock()
self.deploy_operation = DeployAMIOperation(self.ec2_serv, self.security_group_service, self.tag_creator_service)

def test_deploy(self):
ami_datamodel = Mock()
ami_datamodel.storage_size = None
ami_datamodel.inbound_ports = "80"
ami_datamodel.outbound_ports = None
instance = Mock()
instance.tags = [{'Key': 'Name', 'Value': 'my name'}]
self.ec2_serv.create_instance = Mock(return_value=instance)
res = self.deploy_operation.deploy(self.ec2_session, 'my name', 'reservation_id', self.ec2_datamodel,
res = self.deploy_operation.deploy(self.ec2_session,
'my name',
'reservation_id',
self.ec2_datamodel,
ami_datamodel)

self.assertEqual(res.vm_name, 'my name')
Expand All @@ -34,14 +39,14 @@ def test_deploy(self):
self.assertEqual(res.inbound_ports, ami_datamodel.inbound_ports)
self.assertEqual(res.outbound_ports, ami_datamodel.outbound_ports)
self.assertEqual(res.vm_uuid, instance.instance_id)
self.assertTrue(self.tag_creator.get_security_group_tags.called)
self.assertTrue(self.security_group_man.create_security_group.called)
self.assertTrue(self.tag_creator_service.get_security_group_tags.called)
self.assertTrue(self.security_group_service.create_security_group.called)
self.assertTrue(self.ec2_serv.set_ec2_resource_tags.called_with(
self.security_group_man.create_security_group()),
self.tag_creator.get_security_group_tags())
self.security_group_service.create_security_group()),
self.tag_creator_service.get_security_group_tags())

self.assertTrue(self.security_group_man.set_security_group_rules.called_with(
ami_datamodel, self.security_group_man.create_security_group()))
self.assertTrue(self.security_group_service.set_security_group_rules.called_with(
ami_datamodel, self.security_group_service.create_security_group()))

def test_get_block_device_mappings_not_defaults(self):
ami = Mock()
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from unittest import TestCase

import jsonpickle
from cloudshell.cp.aws.common.deploy_data_holder import DeployDataHolder

from cloudshell.cp.aws.domain.deployed_app.operations.app_ports_operation import DeployedAppPortsOperation
from cloudshell.cp.aws.domain.services.model_parser.custom_param_extractor import VmCustomParamsExtractor


class TestDeployedAppPortsOperation(TestCase):
def setUp(self):
self.operation = DeployedAppPortsOperation(VmCustomParamsExtractor())

def test_format_single_inbound(self):
json_str = '{"vmCustomParams":[{"name": "inbound_ports", "value": "80"}]}'
dict = jsonpickle.decode(json_str)
vmdetails = DeployDataHolder(dict)

result = self.operation.get_formated_deployed_app_ports(vmdetails.vmCustomParams)

self.assertEqual(result, 'Inbound ports:\nPort 80 tcp')

def test_format_complex_inbound(self):
json_str = '{"vmCustomParams":[{"name": "inbound_ports", "value": "80; 1200-2300:udp; 26:tcp"}]}'
dict = jsonpickle.decode(json_str)
vmdetails = DeployDataHolder(dict)

result = self.operation.get_formated_deployed_app_ports(vmdetails.vmCustomParams)

self.assertEqual(result, 'Inbound ports:\nPort 80 tcp\nPorts 1200-2300 udp\nPort 26 tcp')

def test_format_single_outbound(self):
json_str = '{"vmCustomParams":[{"name": "outbound_ports", "value": "80"}]}'
dict = jsonpickle.decode(json_str)
vmdetails = DeployDataHolder(dict)

result = self.operation.get_formated_deployed_app_ports(vmdetails.vmCustomParams)

self.assertEqual(result, 'Outbound ports:\nPort 80 tcp')

def test_format_complex_outbound(self):
json_str = '{"vmCustomParams":[{"name": "Outbound_ports", "value": "80; 1200-2300:udp; 26:tcp"}]}'
dict = jsonpickle.decode(json_str)
vmdetails = DeployDataHolder(dict)

result = self.operation.get_formated_deployed_app_ports(vmdetails.vmCustomParams)

self.assertEqual(result, 'Outbound ports:\nPort 80 tcp\nPorts 1200-2300 udp\nPort 26 tcp')

def test_format_complex_inbound_and_outbound(self):
json_str = '{"vmCustomParams":[' \
'{"name": "inbound_ports", "value": "80; 1200-2300:udp; 26:tcp"},' \
'{"name": "Outbound_ports", "value": "1433; 3000-3010:udp; 30:tcp; 26:udp"}]}'
dict = jsonpickle.decode(json_str)
vmdetails = DeployDataHolder(dict)

result = self.operation.get_formated_deployed_app_ports(vmdetails.vmCustomParams)

self.assertEqual(result,
'Inbound ports:\nPort 80 tcp\nPorts 1200-2300 udp\nPort 26 tcp\n\n'
'Outbound ports:\nPort 1433 tcp\nPorts 3000-3010 udp\nPort 30 tcp\nPort 26 udp')


Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from unittest import TestCase

import jsonpickle
from cloudshell.cp.aws.common.deploy_data_holder import DeployDataHolder
from cloudshell.cp.aws.domain.services.model_parser.custom_param_extractor import VmCustomParamsExtractor


class TestVmCustomParamsExtractor(TestCase):
def setUp(self):
pass

def test_extracor(self):
json_str = '{"vmCustomParams":[{"name": "param", "value": "some_value"}]}'
dict = jsonpickle.decode(json_str)
vmdetails = DeployDataHolder(dict)

extracotr = VmCustomParamsExtractor()
param_value = extracotr.get_custom_param_value(vmdetails.vmCustomParams, "param")

self.assertEqual(param_value, "some_value")