feat(armada): adding helm testing framework
- added helm test framework to armada - added helm test status Closes #151 Change-Id: I417cae04b4595ad0d4fd05889d90c83907607c47
This commit is contained in:
committed by
gardlt
parent
70e95d64f5
commit
d5f4378731
@@ -204,8 +204,9 @@ class Armada(object):
|
||||
|
||||
desc = entry.get('description', 'A Chart Group')
|
||||
chart_group = entry.get(KEYWORD_CHARTS, [])
|
||||
test_charts = entry.get('test_charts', False)
|
||||
|
||||
if entry.get('sequenced', False):
|
||||
if entry.get('sequenced', False) or test_charts:
|
||||
chart_wait = True
|
||||
|
||||
LOG.info('Deploying: %s', desc)
|
||||
@@ -213,13 +214,18 @@ class Armada(object):
|
||||
for gchart in chart_group:
|
||||
chart = dotify(gchart['chart'])
|
||||
values = gchart.get('chart').get('values', {})
|
||||
test_chart = gchart.get('chart').get('test', False)
|
||||
pre_actions = {}
|
||||
post_actions = {}
|
||||
|
||||
LOG.info('%s', chart.release)
|
||||
|
||||
if chart.release is None:
|
||||
continue
|
||||
|
||||
if test_chart:
|
||||
chart_wait = True
|
||||
|
||||
# retrieve appropriate timeout value if 'wait' is specified
|
||||
chart_timeout = self.timeout
|
||||
if chart_wait:
|
||||
@@ -271,6 +277,7 @@ class Armada(object):
|
||||
continue
|
||||
|
||||
# do actual update
|
||||
LOG.info('wait: %s', chart_wait)
|
||||
self.tiller.update_release(protoc_chart,
|
||||
prefix_chart,
|
||||
chart.namespace,
|
||||
@@ -297,6 +304,17 @@ class Armada(object):
|
||||
LOG.debug("Cleaning up chart source in %s",
|
||||
chartbuilder.source_directory)
|
||||
|
||||
if test_charts or test_chart:
|
||||
LOG.info('Testing: %s', prefix_chart)
|
||||
resp = self.tiller.testing_release(prefix_chart)
|
||||
test_status = getattr(resp.info.status,
|
||||
'last_test_suite_run', 'FAILED')
|
||||
LOG.info("Test INFO: %s", test_status)
|
||||
if resp:
|
||||
LOG.info("PASSED: %s", prefix_chart)
|
||||
else:
|
||||
LOG.info("FAILED: %s", prefix_chart)
|
||||
|
||||
LOG.info("Performing Post-Flight Operations")
|
||||
self.post_flight_ops()
|
||||
|
||||
|
||||
@@ -173,3 +173,20 @@ class K8s(object):
|
||||
LOG.info('New pod %s deployed', new_pod_name)
|
||||
|
||||
w.stop()
|
||||
|
||||
def wait_get_completed_podphase(self, release, timeout=300):
|
||||
'''
|
||||
:param release - part of namespace
|
||||
:param timeout - time before disconnecting stream
|
||||
'''
|
||||
|
||||
w = watch.Watch()
|
||||
for event in w.stream(self.client.list_pod_for_all_namespaces,
|
||||
timeout_seconds=timeout):
|
||||
pod_name = event['object'].metadata.name
|
||||
|
||||
if release in pod_name:
|
||||
pod_state = event['object'].status.phase
|
||||
if pod_state == 'Succeeded':
|
||||
w.stop()
|
||||
break
|
||||
|
||||
@@ -12,26 +12,33 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import grpc
|
||||
import yaml
|
||||
import grpc
|
||||
|
||||
from hapi.services.tiller_pb2 import ReleaseServiceStub, ListReleasesRequest, \
|
||||
InstallReleaseRequest, UpdateReleaseRequest, UninstallReleaseRequest
|
||||
from hapi.chart.config_pb2 import Config
|
||||
|
||||
from k8s import K8s
|
||||
from ..const import STATUS_DEPLOYED, STATUS_FAILED
|
||||
|
||||
from ..exceptions import tiller_exceptions
|
||||
from ..utils.release import release_prefix
|
||||
|
||||
from hapi.services.tiller_pb2 import GetReleaseContentRequest
|
||||
from hapi.services.tiller_pb2 import GetReleaseStatusRequest
|
||||
from hapi.services.tiller_pb2 import GetVersionRequest
|
||||
from hapi.services.tiller_pb2 import InstallReleaseRequest
|
||||
from hapi.services.tiller_pb2 import ListReleasesRequest
|
||||
from hapi.services.tiller_pb2 import ReleaseServiceStub
|
||||
from hapi.services.tiller_pb2 import TestReleaseRequest
|
||||
from hapi.services.tiller_pb2 import UninstallReleaseRequest
|
||||
from hapi.services.tiller_pb2 import UpdateReleaseRequest
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from ..const import STATUS_DEPLOYED, STATUS_FAILED
|
||||
from ..exceptions import tiller_exceptions as ex
|
||||
from ..utils.release import release_prefix
|
||||
from k8s import K8s
|
||||
|
||||
|
||||
TILLER_PORT = 44134
|
||||
TILLER_VERSION = b'2.5.0'
|
||||
TILLER_TIMEOUT = 300
|
||||
RELEASE_LIMIT = 64
|
||||
RUNTEST_SUCCESS = 9
|
||||
|
||||
# the standard gRPC max message size is 4MB
|
||||
# this expansion comes at a performance penalty
|
||||
@@ -88,7 +95,7 @@ class Tiller(object):
|
||||
]
|
||||
)
|
||||
except Exception:
|
||||
raise tiller_exceptions.ChannelException()
|
||||
raise ex.ChannelException()
|
||||
|
||||
def _get_tiller_pod(self):
|
||||
'''
|
||||
@@ -200,8 +207,8 @@ class Tiller(object):
|
||||
self.delete_resources(
|
||||
release_name, name, 'pod', labels, namespace)
|
||||
except Exception:
|
||||
raise tiller_exceptions.PreUpdateJobDeleteException(name,
|
||||
namespace)
|
||||
raise ex.PreUpdateJobDeleteException(name, namespace)
|
||||
|
||||
LOG.debug("PRE: Could not delete anything, please check yaml")
|
||||
|
||||
try:
|
||||
@@ -213,8 +220,8 @@ class Tiller(object):
|
||||
self.k8s.create_job_action(name, action_type)
|
||||
continue
|
||||
except Exception:
|
||||
raise tiller_exceptions.PreUpdateJobCreateException(name,
|
||||
namespace)
|
||||
raise ex.PreUpdateJobCreateException(name, namespace)
|
||||
|
||||
LOG.debug("PRE: Could not create anything, please check yaml")
|
||||
|
||||
def delete_resource(self, release_name, resource_name, resource_type,
|
||||
@@ -260,7 +267,7 @@ class Tiller(object):
|
||||
self.k8s.create_job_action(name, action_type)
|
||||
continue
|
||||
except Exception:
|
||||
raise tiller_exceptions.PreUpdateJobCreateException()
|
||||
raise ex.PreUpdateJobCreateException()
|
||||
LOG.debug("POST: Could not create anything, please check yaml")
|
||||
|
||||
def list_charts(self):
|
||||
@@ -319,7 +326,8 @@ class Tiller(object):
|
||||
stub.UpdateRelease(
|
||||
release_request, self.timeout, metadata=self.metadata)
|
||||
except Exception:
|
||||
raise tiller_exceptions.ReleaseInstallException(release, namespace)
|
||||
status = self.get_release_status(release)
|
||||
raise ex.ReleaseException(release, status, 'Upgrade')
|
||||
|
||||
self._post_update_actions(post_actions, namespace)
|
||||
|
||||
@@ -331,6 +339,7 @@ class Tiller(object):
|
||||
'''
|
||||
Create a Helm Release
|
||||
'''
|
||||
|
||||
LOG.debug("wait: %s", wait)
|
||||
LOG.debug("timeout: %s", timeout)
|
||||
|
||||
@@ -355,7 +364,95 @@ class Tiller(object):
|
||||
release_request, self.timeout, metadata=self.metadata)
|
||||
|
||||
except Exception:
|
||||
raise tiller_exceptions.ReleaseInstallException(release, namespace)
|
||||
status = self.get_release_status(release)
|
||||
raise ex.ReleaseException(release, status, 'Install')
|
||||
|
||||
def testing_release(self, release, timeout=300, cleanup=True):
|
||||
'''
|
||||
:param release - name of release to test
|
||||
:param timeout - runtime before exiting
|
||||
:param cleanup - removes testing pod created
|
||||
|
||||
:returns - results of test pod
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
|
||||
stub = ReleaseServiceStub(self.channel)
|
||||
release_request = TestReleaseRequest(name=release, timeout=timeout,
|
||||
cleanup=cleanup)
|
||||
|
||||
content = self.get_release_content(release)
|
||||
|
||||
if not len(content.release.hooks):
|
||||
LOG.info('No test found')
|
||||
return False
|
||||
|
||||
if content.release.hooks[0].events[0] == RUNTEST_SUCCESS:
|
||||
test = stub.RunReleaseTest(
|
||||
release_request, self.timeout, metadata=self.metadata)
|
||||
|
||||
if test.running():
|
||||
self.k8s.wait_get_completed_podphase(release)
|
||||
|
||||
test.cancel()
|
||||
|
||||
return self.get_release_status(release)
|
||||
|
||||
except Exception:
|
||||
status = self.get_release_status(release)
|
||||
raise ex.ReleaseException(release, status, 'Test')
|
||||
|
||||
def get_release_status(self, release, version=0):
|
||||
'''
|
||||
:param release - name of release to test
|
||||
:param version - version of release status
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
stub = ReleaseServiceStub(self.channel)
|
||||
status_request = GetReleaseStatusRequest(
|
||||
name=release, version=version)
|
||||
|
||||
return stub.GetReleaseStatus(
|
||||
status_request, self.timeout, metadata=self.metadata)
|
||||
|
||||
except Exception:
|
||||
raise ex.GetReleaseStatusException(release, version)
|
||||
|
||||
def get_release_content(self, release, version=0):
|
||||
'''
|
||||
:param release - name of release to test
|
||||
:param version - version of release status
|
||||
|
||||
'''
|
||||
|
||||
try:
|
||||
stub = ReleaseServiceStub(self.channel)
|
||||
status_request = GetReleaseContentRequest(
|
||||
name=release, version=version)
|
||||
|
||||
return stub.GetReleaseContent(
|
||||
status_request, self.timeout, metadata=self.metadata)
|
||||
|
||||
except Exception:
|
||||
raise ex.GetReleaseContentException(release, version)
|
||||
|
||||
def tiller_version(self):
|
||||
'''
|
||||
:returns - tiller version
|
||||
'''
|
||||
try:
|
||||
stub = ReleaseServiceStub(self.channel)
|
||||
release_request = GetVersionRequest()
|
||||
|
||||
return stub.GetVersion(
|
||||
release_request, self.timeout, metadata=self.metadata)
|
||||
|
||||
except Exception:
|
||||
raise ex.TillerVersionException()
|
||||
|
||||
def uninstall_release(self, release, disable_hooks=False, purge=True):
|
||||
'''
|
||||
@@ -375,7 +472,8 @@ class Tiller(object):
|
||||
release_request, self.timeout, metadata=self.metadata)
|
||||
|
||||
except Exception:
|
||||
raise tiller_exceptions.ReleaseUninstallException(release)
|
||||
status = self.get_release_status(release)
|
||||
raise ex.ReleaseException(release, status, 'Delete')
|
||||
|
||||
def chart_cleanup(self, prefix, charts):
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user