@ -2,6 +2,7 @@
from __future__ import absolute_import , print_function
from __future__ import absolute_import , print_function
import os
import os
import time
from lib . cloud import (
from lib . cloud import (
CloudProvider ,
CloudProvider ,
@ -12,6 +13,10 @@ from lib.cloud import (
from lib . util import (
from lib . util import (
find_executable ,
find_executable ,
display ,
display ,
ApplicationError ,
is_shippable ,
ConfigParser ,
SubprocessError ,
)
)
from lib . docker_util import (
from lib . docker_util import (
@ -22,6 +27,14 @@ from lib.docker_util import (
get_docker_container_id ,
get_docker_container_id ,
)
)
from lib . core_ci import (
AnsibleCoreCI ,
)
from lib . http import (
HttpClient ,
)
class VcenterProvider ( CloudProvider ) :
class VcenterProvider ( CloudProvider ) :
""" VMware vcenter/esx plugin. Sets up cloud resources for tests. """
""" VMware vcenter/esx plugin. Sets up cloud resources for tests. """
@ -40,11 +53,23 @@ class VcenterProvider(CloudProvider):
self . image = ' quay.io/ansible/vcenter-test-container:1.5.0 '
self . image = ' quay.io/ansible/vcenter-test-container:1.5.0 '
self . container_name = ' '
self . container_name = ' '
# VMWare tests can be run on govcsim or baremetal, either BYO with a static config
# file or hosted in worldstream. Using an env var value of 'worldstream' with appropriate
# CI credentials will deploy a dynamic baremetal environment. The simulator is the default
# if no other config if provided.
self . vmware_test_platform = os . environ . get ( ' VMWARE_TEST_PLATFORM ' , ' ' )
self . aci = None
self . insecure = False
self . endpoint = ' '
self . hostname = ' '
self . port = 443
def filter ( self , targets , exclude ) :
def filter ( self , targets , exclude ) :
""" Filter out the cloud tests when the necessary config and resources are not available.
""" Filter out the cloud tests when the necessary config and resources are not available.
: type targets : tuple [ TestTarget ]
: type targets : tuple [ TestTarget ]
: type exclude : list [ str ]
: type exclude : list [ str ]
"""
"""
if self . vmware_test_platform is None or ' govcsim ' :
docker = find_executable ( ' docker ' , required = False )
docker = find_executable ( ' docker ' , required = False )
if docker :
if docker :
@ -57,33 +82,54 @@ class VcenterProvider(CloudProvider):
exclude . append ( skip )
exclude . append ( skip )
display . warning ( ' Excluding tests marked " %s " which require the " docker " command: %s '
display . warning ( ' Excluding tests marked " %s " which require the " docker " command: %s '
% ( skip . rstrip ( ' / ' ) , ' , ' . join ( skipped ) ) )
% ( skip . rstrip ( ' / ' ) , ' , ' . join ( skipped ) ) )
else :
if os . path . isfile ( self . config_static_path ) :
return
aci = self . _create_ansible_core_ci ( )
if os . path . isfile ( aci . ci_key ) :
return
if is_shippable ( ) :
return
super ( VcenterProvider , self ) . filter ( targets , exclude )
def setup ( self ) :
def setup ( self ) :
""" Setup the cloud resource before delegation and register a cleanup callback. """
""" Setup the cloud resource before delegation and register a cleanup callback. """
super ( VcenterProvider , self ) . setup ( )
super ( VcenterProvider , self ) . setup ( )
self . _set_cloud_config ( ' vmware_test_platform ' , self . vmware_test_platform )
if self . _use_static_config ( ) :
if self . _use_static_config ( ) :
self . _setup_static ( )
self . _setup_static ( )
elif self . vmware_test_platform == ' worldstream ' :
self . _setup_dynamic_baremetal ( )
else :
else :
self . _setup_dynamic ( )
self . _setup_dynamic _simulator ( )
def get_docker_run_options ( self ) :
def get_docker_run_options ( self ) :
""" Get any additional options needed when delegating tests to a docker container.
""" Get any additional options needed when delegating tests to a docker container.
: rtype : list [ str ]
: rtype : list [ str ]
"""
"""
if self . managed :
if self . managed and self . vmware_test_platform != ' worldstream ' :
return [ ' --link ' , self . DOCKER_SIMULATOR_NAME ]
return [ ' --link ' , self . DOCKER_SIMULATOR_NAME ]
return [ ]
return [ ]
def cleanup ( self ) :
def cleanup ( self ) :
""" Clean up the cloud resource and any temporary configuration files after tests complete. """
""" Clean up the cloud resource and any temporary configuration files after tests complete. """
if self . vmware_test_platform == ' worldstream ' :
if self . aci :
self . aci . stop ( )
if self . container_name :
if self . container_name :
docker_rm ( self . args , self . container_name )
docker_rm ( self . args , self . container_name )
super ( VcenterProvider , self ) . cleanup ( )
super ( VcenterProvider , self ) . cleanup ( )
def _setup_dynamic ( self ) :
def _setup_dynamic _simulator ( self ) :
""" Create a vcenter simulator using docker. """
""" Create a vcenter simulator using docker. """
container_id = get_docker_container_id ( )
container_id = get_docker_container_id ( )
@ -139,8 +185,62 @@ class VcenterProvider(CloudProvider):
ipaddress = results [ 0 ] [ ' NetworkSettings ' ] [ ' IPAddress ' ]
ipaddress = results [ 0 ] [ ' NetworkSettings ' ] [ ' IPAddress ' ]
return ipaddress
return ipaddress
def _setup_dynamic_baremetal ( self ) :
""" Request Esxi credentials through the Ansible Core CI service. """
display . info ( ' Provisioning %s cloud environment. ' % self . platform ,
verbosity = 1 )
config = self . _read_config_template ( )
aci = self . _create_ansible_core_ci ( )
if not self . args . explain :
response = aci . start ( )
self . aci = aci
config = self . _populate_config_template ( config , response )
self . _write_config ( config )
def _create_ansible_core_ci ( self ) :
"""
: rtype : AnsibleCoreCI
"""
return AnsibleCoreCI ( self . args , ' vmware ' , ' vmware ' ,
persist = False , stage = self . args . remote_stage ,
provider = ' vmware ' )
def _setup_static ( self ) :
def _setup_static ( self ) :
raise NotImplementedError ( )
parser = ConfigParser ( )
parser . read ( self . config_static_path )
self . endpoint = parser . get ( ' DEFAULT ' , ' vcenter_hostname ' )
self . port = parser . get ( ' DEFAULT ' , ' vcenter_port ' )
if parser . get ( ' DEFAULT ' , ' vmware_validate_certs ' ) . lower ( ) in ( ' no ' , ' false ' ) :
self . insecure = True
self . _wait_for_service ( )
def _wait_for_service ( self ) :
""" Wait for the VCenter service endpoint to accept connections. """
if self . args . explain :
return
client = HttpClient ( self . args , always = True , insecure = self . insecure )
endpoint = ' https:// %s : %s ' % ( self . endpoint , self . port )
for i in range ( 1 , 30 ) :
display . info ( ' Waiting for VCenter service: %s ' % endpoint , verbosity = 1 )
try :
client . get ( endpoint )
return
except SubprocessError :
pass
time . sleep ( 10 )
raise ApplicationError ( ' Timeout waiting for VCenter service. ' )
class VcenterEnvironment ( CloudEnvironment ) :
class VcenterEnvironment ( CloudEnvironment ) :
@ -149,6 +249,22 @@ class VcenterEnvironment(CloudEnvironment):
"""
"""
: rtype : CloudEnvironmentConfig
: rtype : CloudEnvironmentConfig
"""
"""
vmware_test_platform = self . _get_cloud_config ( ' vmware_test_platform ' )
if vmware_test_platform == ' worldstream ' :
parser = ConfigParser ( )
parser . read ( self . config_path )
# Most of the test cases use ansible_vars, but we plan to refactor these
# to use env_vars, output both for now
env_vars = dict (
( key . upper ( ) , value ) for key , value in parser . items ( ' DEFAULT ' ) )
ansible_vars = dict (
resource_prefix = self . resource_prefix ,
)
ansible_vars . update ( dict ( parser . items ( ' DEFAULT ' ) ) )
else :
env_vars = dict (
env_vars = dict (
VCENTER_HOST = self . _get_cloud_config ( ' vcenter_host ' ) ,
VCENTER_HOST = self . _get_cloud_config ( ' vcenter_host ' ) ,
)
)