from cloudshell.cp.core import DriverRequestParser
from cloudshell.cp.core.models import DriverResponse, DeployApp, DeployAppResult, PrepareCloudInfra, CreateKeys, \
PrepareSubnet, RemoveVlan, SetVlan
from cloudshell.shell.core.resource_driver_interface import ResourceDriverInterface
from cloudshell.cp.core.models import DriverResponse
from cloudshell.shell.core.driver_context import InitCommandContext, AutoLoadCommandContext, ResourceCommandContext, \
AutoLoadAttribute, AutoLoadDetails, CancellationContext, ResourceRemoteCommandContext
from cloudshell.shell.core.session.cloudshell_session import CloudShellSessionContext
from cloudshell.shell.core.session.logging_session import LoggingSessionContext
from data_model import *
from sdk.heavenly_cloud_service import *
from heavenly_cloud_service_wrapper import HeavenlyCloudServiceWrapper
from cloudshell.core.context.error_handling_context import ErrorHandlingContext
import json
# from data_model import * # run 'shellfoundry generate' to generate data model classes
class L2HeavenlyCloudShellDriver(ResourceDriverInterface):
def __init__(self):
"""
ctor must be without arguments, it is created with reflection at run time
"""
self.request_parser = DriverRequestParser()
def initialize(self, context):
"""
Initialize the driver session, this function is called everytime a new instance of the driver is created
This is a good place to load and cache the driver configuration, initiate sessions etc.
:param InitCommandContext context: the context the command runs on
"""
self.request_parser = DriverRequestParser()
self.request_parser.add_deployment_model(HeavenlyCloudAngelDeploymentModel)
self.request_parser.add_deployment_model(HeavenlyCloudManDeploymentModel)
#
def get_inventory(self, context):
## uncomment - if there is nothing to validate
# return AutoLoadDetails([], [])
# read from context
cloud_provider_resource = L2HeavenlyCloudShell.create_from_context(context)
with LoggingSessionContext(context) as logger, ErrorHandlingContext(logger):
self._log(logger, 'get_inventory_context_json', context)
# validating
if cloud_provider_resource.name == 'evil':
raise ValueError('evil cannot use heaven ')
if cloud_provider_resource.region == 'sun':
raise ValueError('invalid region, sorry cannot deploy instances on the sun')
# using your cloud provider sdk
if not HeavenlyCloudService.can_connect(cloud_provider_resource.user, cloud_provider_resource.password,
context.resource.address): # TODO add address to resource (gal shellfoundry team)
raise ValueError('could not connect using given credentials')
# discovering - using your prefered custom cloud service you can discover and then update values
if not cloud_provider_resource.heaven_cloud_color:
cloud_provider_resource.heaven_cloud_color = HeavenlyCloudService.get_prefered_cloud_color()
return cloud_provider_resource.create_autoload_details()
#
#
def Deploy(self, context, request, cancellation_context=None):
"""
Deploy
:param ResourceCommandContext context:
:param str request: A JSON string with the list of requested deployment actions
:param CancellationContext cancellation_context:
:return:
:rtype: str
"""
with LoggingSessionContext(context) as logger, ErrorHandlingContext(logger):
with CloudShellSessionContext(context) as cloudshell_session:
self._log(logger, 'deploy_request', request)
self._log(logger, 'deploy_context', context)
# parse the json strings into action objects
cloud_provider_resource = L2HeavenlyCloudShell.create_from_context(context)
actions = self.request_parser.convert_driver_request_to_actions(request)
# extract DeployApp action
deploy_action = single(actions, lambda x: isinstance(x, DeployApp))
# if we have multiple supported deployment options use the 'deploymentPath' property
# to decide which deployment option to use.
deployment_name = deploy_action.actionParams.deployment.deploymentPath
if deployment_name == 'L2HeavenlyCloudShell.HeavenlyCloudAngelDeployment':
deploy_result = HeavenlyCloudServiceWrapper.deploy_angel(context, cloudshell_session, cloud_provider_resource, deploy_action, cancellation_context)
elif deployment_name == 'L2HeavenlyCloudShell.HeavenlyCloudManDeployment':
deploy_result = HeavenlyCloudServiceWrapper.deploy_man(context, cloudshell_session,cloud_provider_resource,deploy_action, cancellation_context)
else:
raise ValueError(deployment_name + ' deployment option is not supported.')
self._log(logger, 'deployment_name', deployment_name)
self._log(logger, 'deploy_result', deploy_result)
return DriverResponse([deploy_result]).to_driver_response_json()
def PowerOn(self, context, ports):
"""
Will power on the compute resource
:param ResourceRemoteCommandContext context:
:param ports:
"""
with LoggingSessionContext(context) as logger, ErrorHandlingContext(logger):
self._log(logger, 'power_on_context', context)
self._log(logger, 'power_on_ports', ports)
cloud_provider_resource = L2HeavenlyCloudShell.create_from_context(context)
resource_ep = context.remote_endpoints[0]
deployed_app_dict = json.loads(resource_ep.app_context.deployed_app_json)
HeavenlyCloudServiceWrapper.power_on(cloud_provider_resource, deployed_app_dict['vmdetails']['uid'])
def PowerOff(self, context, ports):
"""
Will power off the compute resource
:param ResourceRemoteCommandContext context:
:param ports:
"""
with LoggingSessionContext(context) as logger, ErrorHandlingContext(logger):
self._log(logger, 'power_off_context', context)
self._log(logger, 'power_off_ports', ports)
cloud_provider_resource = L2HeavenlyCloudShell.create_from_context(context)
resource_ep = context.remote_endpoints[0]
deployed_app_dict = json.loads(resource_ep.app_context.deployed_app_json)
HeavenlyCloudServiceWrapper.power_off(cloud_provider_resource, deployed_app_dict['vmdetails']['uid'])
def PowerCycle(self, context, ports, delay):
pass
def DeleteInstance(self, context, ports):
"""
Will delete the compute resource
:param ResourceRemoteCommandContext context:
:param ports:
"""
with LoggingSessionContext(context) as logger, ErrorHandlingContext(logger):
self._log(logger, 'DeleteInstance_context', context)
self._log(logger, 'DeleteInstance_ports', ports)
cloud_provider_resource = L2HeavenlyCloudShell.create_from_context(context)
resource_ep = context.remote_endpoints[0]
deployed_app_dict = json.loads(resource_ep.app_context.deployed_app_json)
HeavenlyCloudServiceWrapper.delete_instance(cloud_provider_resource, deployed_app_dict['vmdetails']['uid'])
def GetVmDetails(self, context, requests, cancellation_context):
"""
:param ResourceCommandContext context:
:param str requests:
:param CancellationContext cancellation_context:
:return:
"""
with LoggingSessionContext(context) as logger, ErrorHandlingContext(logger):
self._log(logger, 'GetVmDetails_context', context)
self._log(logger, 'GetVmDetails_requests', requests)
cloud_provider_resource = L2HeavenlyCloudShell.create_from_context(context)
result = HeavenlyCloudServiceWrapper.get_vm_details(logger, cloud_provider_resource, cancellation_context,
requests)
result_json = json.dumps(result, default=lambda o: o.__dict__, sort_keys=True, separators=(',', ':'))
self._log(logger, 'GetVmDetails_result', result_json)
return result_json
def remote_refresh_ip(self, context, ports, cancellation_context):
"""
Will update the address of the computer resource on the Deployed App resource in cloudshell
:param ResourceRemoteCommandContext context:
:param ports:
:param CancellationContext cancellation_context:
:return:
"""
with LoggingSessionContext(context) as logger, ErrorHandlingContext(logger):
with CloudShellSessionContext(context) as cloudshell_session:
self._log(logger, 'remote_refresh_ip_context', context)
self._log(logger, 'remote_refresh_ip_ports', ports)
self._log(logger, 'remote_refresh_ip_cancellation_context', cancellation_context)
cloud_provider_resource = L2HeavenlyCloudShell.create_from_context(context)
deployed_app_dict = json.loads(context.remote_endpoints[0].app_context.deployed_app_json)
remote_ep = context.remote_endpoints[0]
deployed_app_private_ip = remote_ep.address
deployed_app_public_ip = None
public_ip_att = first_or_default(deployed_app_dict['attributes'],lambda x:x['name'] == 'Public IP')
if public_ip_att:
deployed_app_public_ip = public_ip_att['value']
deployed_app_fullname = remote_ep.fullname
vm_instance_id = deployed_app_dict['vmdetails']['uid']
HeavenlyCloudServiceWrapper.remote_refresh_ip(cloud_provider_resource, cancellation_context, cloudshell_session, deployed_app_fullname, vm_instance_id, deployed_app_private_ip, deployed_app_public_ip)
def ApplyConnectivityChanges(self, context, request):
"""
Configures VLANs on multiple ports or port-channels
:param ResourceCommandContext context: The context object for the command with resource and reservation info
:param str request: A JSON string with the list of requested connectivity changes
:return: a json object with the list of connectivity changes which were carried out by the driver
:rtype: str
"""
with LoggingSessionContext(context) as logger, ErrorHandlingContext(logger):
self._log(logger, 'ApplyConnectivityChanges_request', request)
self._log(logger, 'ApplyConnectivityChanges_context', context)
# parse the json strings into action objects
cloud_provider_resource = L2HeavenlyCloudShell.create_from_context(context)
actions = self.request_parser.convert_driver_request_to_actions(request)
# extract Set/Remove vlan actions
remove_vlan_actions = filter(lambda x: isinstance(x, RemoveVlan), actions)
remove_vlan_results = HeavenlyCloudServiceWrapper.disconnect_all(logger, cloud_provider_resource, remove_vlan_actions)
set_vlan_actions = filter(lambda x: isinstance(x, SetVlan), actions)
set_vlan_results = HeavenlyCloudServiceWrapper.connect_all(logger, cloud_provider_resource, set_vlan_actions)
return DriverResponse(remove_vlan_results + set_vlan_results).to_driver_response_json()
#
def SetAppSecurityGroups(self, context, request):
"""
:param ResourceCommandContext context:
:param str request:
:return:
:rtype: str
"""
pass
#
def cleanup(self):
"""
Destroy the driver session, this function is called everytime a driver instance is destroyed
This is a good place to close any open sessions, finish writing to log files, etc.
"""
pass
def _log(self, logger, name, obj):
if not obj:
logger.info(name + 'Value is None')
if not self._is_primitive(obj):
name = name + '__json_serialized'
obj = json.dumps(obj, default=lambda o: o.__dict__, sort_keys=True, separators=(',', ':'))
logger.info(name)
logger.info(obj)
def _is_primitive(self, thing):
primitive = (int, str, bool, float, unicode)
return isinstance(thing, primitive)