Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
doppleware committed Mar 30, 2016
2 parents 64746bc + 08d6477 commit 063b974
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 48 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ python:
- "2.7"

install:
- pip install -r package/requirements.txt
- pip install cloudshell-shell-core
- pip install -r package/requirements.txt --extra-index-url https://testpypi.python.org/pypi
- pip install cloudshell-shell-core --extra-index-url https://testpypi.python.org/pypi
- pip install -r test_requirements.txt
- pip install coveralls

Expand Down
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
[![Build Status](https://travis-ci.org/QualiSystems/vCenterShell.svg?branch=master)](https://travis-ci.org/QualiSystems/vCenterShell) [![Coverage Status](https://coveralls.io/repos/QualiSystems/vCenterShell/badge.svg?branch=develop&service=github)](https://coveralls.io/github/QualiSystems/vCenterShell?branch=develop) [![Code Climate](https://codeclimate.com/github/QualiSystems/vCenterShell/badges/gpa.svg)](https://codeclimate.com/github/QualiSystems/vCenterShell) [ ![Foo](https://qualisystems.getbadges.io/shield/company/qualisystems) ](https://getbadges.io) [![Stories in Ready](https://badge.waffle.io/QualiSystems/vCenterShell.svg?label=ready&title=Ready)](http://waffle.io/QualiSystems/vCenterShell) [![Join the chat at https://gitter.im/QualiSystems/vCenterShell](https://badges.gitter.im/QualiSystems/vCenterShell.svg)](https://gitter.im/QualiSystems/vCenterShell?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Analytics](https://ga-beacon.appspot.com/UA-72194260-1/QualiSystems/vCenterShell)](https://github.com/QualiSystems/vCenterShell/)

A lightweight CloudShell 'shell' that allows integrating with vCenter as an app deployment option.
A repository for projects providing out of the box capabilities within CloudShell to define VMWare vCenter instances in CloudShell and leverage vCenter's capabilities to deploy and connect apps in CloudShell sandboxes.

## Requirements
## Projects
* **Deployment Drivers**

These projects extend CloudShell apps with new deployment types
* **deploy_from_image**
App deployment type driver for deploying from vCenter OVF images
* **deploy_from_template**
App deployment type driver for cloning from vCenter templates


* **package**

The vCenter Python package hosted in [PyPi](https://pypi.python.org/). The package contains most of the logic relate
to working with the vCenter API.

* **vcentershell_driver**

The CloudShell driver for controlling vCenter via CloudShell.

## Installation
* [QualiSystems CloudShell 7.0](http://www.qualisystems.com/products/cloudshell/cloudshell-overview/)
* [pyvmomi 6.0](https://github.com/vmware/pyvmomi)
* [jsonpickle latest](https://jsonpickle.github.io/)


## Getting Started

1. Download vCenterShell.zip from Releases page
Expand Down
14 changes: 10 additions & 4 deletions environment_scripts/env_setup/setup_script.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# coding=utf-8
from multiprocessing.pool import ThreadPool
from threading import Lock

Expand All @@ -16,7 +15,9 @@ class EnvironmentSetup(object):

def __init__(self):
self.reservation_id = helpers.get_reservation_context_details().id
self.logger = qs_logger.get_qs_logger(name="CloudShell Sandbox Setup", reservation_id=self.reservation_id)
self.logger = qs_logger.get_qs_logger(log_file_prefix="CloudShell Sandbox Setup",
log_group=self.reservation_id,
log_category='Setup')

@profileit(scriptName='Setup')
def execute(self):
Expand Down Expand Up @@ -62,6 +63,7 @@ def _try_exeucte_autoload(self, api, reservation_details, deploy_result, resourc
"""

if deploy_result is None:
self.logger.info("No apps to discover")
api.WriteMessageToReservationOutput(reservationId=self.reservation_id, message='No apps to discover')
return

Expand Down Expand Up @@ -162,6 +164,7 @@ def _run_async_power_on_refresh_ip_install(self, api, reservation_details, deplo
api.WriteMessageToReservationOutput(
reservationId=self.reservation_id,
message='No resources to power on or install')
self._validate_all_apps_deployed(deploy_results)
return

pool = ThreadPool(len(resources))
Expand All @@ -184,7 +187,10 @@ def _run_async_power_on_refresh_ip_install(self, api, reservation_details, deplo
if not res[0]:
raise Exception("Reservation is Active with Errors - " + res[1])

if deploy_results and hasattr(deploy_results, "ResultItems"):
self._validate_all_apps_deployed(deploy_results)

def _validate_all_apps_deployed(self, deploy_results):
if deploy_results is not None:
for deploy_res in deploy_results.ResultItems:
if not deploy_res.Success:
raise Exception("Reservation is Active with Errors - " + deploy_res.Error)
Expand Down Expand Up @@ -216,7 +222,7 @@ def _power_on_refresh_ip_install(self, api, lock, message_status, resource, depl
resource_details = api.GetResourceDetails(deployed_app_name)

# check if deployed app
if hasattr(resource_details, "VmDetails"):
if not hasattr(resource_details.VmDetails, "UID"):
self.logger.debug("Resource {0} is not a deployed app, nothing to do with it".format(deployed_app_name))
return True, ""

Expand Down
4 changes: 3 additions & 1 deletion environment_scripts/env_teardown/teardown_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
class EnvironmentTeardown:
def __init__(self):
self.reservation_id = helpers.get_reservation_context_details().id
self.logger = qs_logger.get_qs_logger(name="CloudShell Sandbox Teardown", reservation_id=self.reservation_id)
self.logger = qs_logger.get_qs_logger(log_file_prefix="CloudShell Sandbox Teardown",
log_group=self.reservation_id,
log_category='Teardown')

@profileit(scriptName="Teardown")
def execute(self):
Expand Down
8 changes: 4 additions & 4 deletions orchestration_service/context_based_logger_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def create_logger_for_context(self, logger_name, context):
:param logger_name:
:type logger_name: str
:param context:
:return:
:return: logging.Logger
"""
if self._is_instance_of(context, 'AutoLoadCommandContext'):
reservation_id = 'Autoload'
Expand All @@ -23,9 +23,9 @@ def create_logger_for_context(self, logger_name, context):
handler_name = context.remote_endpoints[0].name
else:
raise Exception(ContextBasedLoggerFactory.UNSUPPORTED_CONTEXT_PROVIDED, context)
logger = get_qs_logger(name=logger_name,
handler_name=handler_name,
reservation_id=reservation_id)
logger = get_qs_logger(log_file_prefix=handler_name,
log_group=reservation_id,
log_category=logger_name)
return logger

@staticmethod
Expand Down
4 changes: 2 additions & 2 deletions orchestration_service/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(self):
def deploy(self, context):
"""
Deploys app from template
:type context: cloudshell.shell.core.driver_context.ResourceCommandContext
:type context: cloudshell.shell.core.context.ResourceCommandContext
"""
logger = self.context_based_logger_factory.create_logger_for_context(
logger_name='DeployAppOrchestrationDriver',
Expand Down Expand Up @@ -223,7 +223,7 @@ def _try_execute_autoload(self, session, reservation_id, deployed_app_name, logg
exc.rawxml))
self._write_message(deployed_app_name, reservation_id, session,
'discovery failed: {1}'.format(deployed_app_name, exc.message))
raise
raise

except Exception as exc:
print "Error executing Autoload command on deployed app {0}. Error: {1}".format(deployed_app_name, str(exc))
Expand Down
4 changes: 2 additions & 2 deletions package/cloudshell/cp/vcenter/commands/power_manager_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ def power_off(self, si, logger, session, vcenter_data_model, vm_uuid, resource_f
vm = self.pv_service.find_by_uuid(si, vm_uuid)

if vm.summary.runtime.powerState == 'poweredOff':
_logger.info('vm already powered off')
logger.info('vm already powered off')
task_result = 'already powered off'
else:
# hard power off
logger.info('{0} powering of vm'.format(vcenter_data_model.shutdown_method))
if vcenter_data_model.shutdown_method.lower() == 'soft':
if vcenter_data_model.shutdown_method.lower() != 'soft':
task = vm.PowerOff()
task_result = self.synchronous_task_waiter.wait_for_task(task=task,
logger=logger,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ def create_logger_for_context(self, logger_name, context):
handler_name = context.remote_endpoints[0].name
else:
raise Exception(ContextBasedLoggerFactory.UNSUPPORTED_CONTEXT_PROVIDED, context)
logger = get_qs_logger(name=logger_name,
handler_name=handler_name,
reservation_id=reservation_id)
logger = get_qs_logger(log_file_prefix=handler_name,
log_group=reservation_id,
log_category=logger_name)
return logger

@staticmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def execute_command_with_connection(self, context, command, *args):
Note: session & vcenter_data_model objects will be injected dynamically to the command
:param command:
:param context: instance of ResourceCommandContext or AutoLoadCommandContext
:type context: cloudshell.shell.core.driver_context.ResourceCommandContext
:type context: cloudshell.shell.core.context.ResourceCommandContext
:param args:
"""

Expand Down
54 changes: 51 additions & 3 deletions package/cloudshell/tests/test_commands/test_power_management_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,54 @@


class TestVirtualMachinePowerManagementCommand(TestCase):
def test_power_off_already(self):
vm_uuid = 'uuid'
si = Mock(spec=vim.ServiceInstance)
vm = Mock(spec=vim.VirtualMachine)
vm.summary = Mock()
vm.summary.runtime = Mock()
vm.summary.runtime.powerState = 'poweredOff'
session = Mock()
pv_service = Mock()
pv_service.find_by_uuid = Mock(return_value=vm)

power_manager = VirtualMachinePowerManagementCommand(pv_service, Mock())

# act
res = power_manager.power_off(si=si,
logger=Mock(),
session=session,
vcenter_data_model=Mock(),
vm_uuid=vm_uuid,
resource_fullname=None)

# assert
self.assertTrue(res, 'already powered off')
self.assertFalse(vm.PowerOn.called)

def test_power_on_already(self):
vm_uuid = 'uuid'
si = Mock(spec=vim.ServiceInstance)
vm = Mock(spec=vim.VirtualMachine)
vm.summary = Mock()
vm.summary.runtime = Mock()
vm.summary.runtime.powerState = 'poweredOn'
session = Mock()
pv_service = Mock()
pv_service.find_by_uuid = Mock(return_value=vm)

power_manager = VirtualMachinePowerManagementCommand(pv_service, Mock())

# act
res = power_manager.power_on(si=si,
logger=Mock(),
session=session,
vm_uuid=vm_uuid,
resource_fullname=None)

# assert
self.assertTrue(res, 'already powered on')
self.assertFalse(vm.PowerOn.called)

def test_power_on(self):
# arrange
Expand Down Expand Up @@ -68,7 +116,7 @@ def test_power_off_soft(self):

# assert
self.assertTrue(res)
self.assertTrue(vm.PowerOff.called)
self.assertTrue(vm.ShutdownGuest.called)
self.assertTrue(power_manager._connect_to_vcenter.called_with(vcenter_name))
self.assertTrue(power_manager._get_vm.called_with(si, vm_uuid))
self.assertTrue(synchronous_task_waiter.wait_for_task.called_with(task))
Expand Down Expand Up @@ -105,7 +153,7 @@ def test_power_off_hard(self):

# assert
self.assertTrue(res)
self.assertTrue(vm.ShutdownGuest.called)
self.assertTrue(vm.PowerOff.called)
self.assertTrue(power_manager._connect_to_vcenter.called_with(vcenter_name))
self.assertTrue(power_manager._get_vm.called_with(si, vm_uuid))
self.assertTrue(synchronous_task_waiter.wait_for_task.called_with(task))
self.assertTrue(synchronous_task_waiter.wait_for_task.called_with(task))
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from unittest import TestCase
from cloudshell.shell.core.driver_context import ResourceCommandContext, \
from cloudshell.shell.core.context import ResourceCommandContext, \
ReservationContextDetails, ResourceContextDetails, ConnectivityContext
from mock import Mock, create_autospec

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from pyVmomi import vim
from cloudshell.cp.vcenter.common.vcenter.vmomi_service import pyVmomiService
from cloudshell.tests.utils.testing_credentials import TestCredentials
logger = get_qs_logger()


class TestVmomiService(unittest.TestCase):
Expand All @@ -34,7 +33,6 @@ def integration_clone_vm_destory(self):
now = datetime.now()
res = pv_service.clone_vm(clone_params=params,
logger=Mock())
logger.debug('clone took: %s' % (str(datetime.now() - now)))

'#assert'
self.assertTrue(type(res.vm), vim.VirtualMachine)
Expand Down
39 changes: 19 additions & 20 deletions package/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,25 @@
with open('requirements.txt') as f_required:
required = f_required.read().splitlines()


setup(
name="cloudshell-cp-vcenter",
author="Quali",
author_email="[email protected]",
description=("This shell enables setting up vCenter as a cloud provider in"
"CloudShell. It supports connectivity, deployment and management operations"
"used for Cloudshel sanboxes."),
packages=find_packages(),
test_suite='nose.collector',
test_requires=['Nose'],
package_data={'': ['*.txt']},
install_requires=required,
version=version_from_file,
include_package_data=True,
keywords = "sandbox cloud virtualization vcenter cmp cloudshell",
classifiers=[
"Development Status :: 4 - Beta",
"Topic :: Software Development :: Libraries",
"License :: OSI Approved :: Apache Software License",
]
name="cloudshell-cp-vcenter",
author="Quali",
author_email="[email protected]",
description=("This shell enables setting up vCenter as a cloud provider in"
"CloudShell. It supports connectivity, deployment and management operations"
"used for Cloudshel sanboxes."),
packages=find_packages(),
test_suite='nose.collector',
test_requires=['Nose'],
package_data={'': ['*.txt']},
install_requires=required,
version=version_from_file,
include_package_data=True,
keywords="sandbox cloud virtualization vcenter cmp cloudshell",
classifiers=[
"Development Status :: 4 - Beta",
"Topic :: Software Development :: Libraries",
"License :: OSI Approved :: Apache Software License",
]

)
4 changes: 3 additions & 1 deletion vlan_service_scripts/connect/connect_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
class ConnectAll:
def __init__(self):
self.reservation_id = helpers.get_reservation_context_details().id
self.logger = qs_logger.get_qs_logger(name="Connect All", reservation_id=self.reservation_id)
self.logger = qs_logger.get_qs_logger(log_file_prefix='Connect_All',
log_group=self.reservation_id,
log_category="Connect All")

def execute(self):
api = helpers.get_api_session()
Expand Down

0 comments on commit 063b974

Please sign in to comment.