d229d52292
This changes unsequenced chart group deployments, such that each chart in the group is deployed in parallel, including the install/upgrade, wait, and tests. Previously, whether and when to wait was entangled with whether or not the chart group was sequenced, since running helm install/upgrade's native wait (which cannot be run later) and armada's labels based wait, delayed (or even prevented in the case of failure) the next chart from being deployed, which is the intention for sequenced, but not for unsequenced. With this patchset, sequencing and waiting are now orthogonal. Hence we can now allow the user to explictly specify whether to wait, which this patchset does for the case of helm's native wait via a new `wait.native.enabled` flag, which defaults to true. Previously, armada's labels-based wait sometimes occurred both between charts and at the end of the chart group. It now occurs once directly after chart deployment. Previously, passing armada's --wait was documented to be equivalent to forcing sequencing of chart groups, however helm tests did not run in sequence as they normally would with sequenced chart groups, they now do. Since chart deploys can now occur in parallel, log messages for each become interleaved, and thus when armada is deploying a chart, log messages are updated to contain identifying information about which chart deployment they are for. Change-Id: I9d13245c40887712333aaccfb044dcdc4b83988e
143 lines
4.3 KiB
Python
143 lines
4.3 KiB
Python
# Copyright 2010 United States Government as represented by the
|
|
# Administrator of the National Aeronautics and Space Administration.
|
|
# Copyright 2015 Hewlett-Packard Development Company, L.P.
|
|
# Copyright 2017 AT&T Intellectual Property.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import mock
|
|
import random
|
|
import string
|
|
import testtools
|
|
import threading
|
|
import uuid
|
|
|
|
_mock_thread_safe = False
|
|
_mock_call_lock = threading.RLock()
|
|
|
|
|
|
# TODO(seaneagan): Get this working.
|
|
def makeMockThreadSafe():
|
|
'''
|
|
This attempts to make a subset of the mock library thread safe using
|
|
locking, so that the mock call records are accurate.
|
|
'''
|
|
global _mock_thread_safe
|
|
if not _mock_thread_safe:
|
|
unsafe_mock_call = mock.CallableMixin._mock_call
|
|
|
|
def safe_mock_call(*args, **kwargs):
|
|
with _mock_call_lock:
|
|
return unsafe_mock_call(*args, **kwargs)
|
|
|
|
mock.CallableMixin._mock_call = safe_mock_call
|
|
|
|
_mock_thread_safe = True
|
|
|
|
|
|
def rand_uuid_hex():
|
|
"""Generate a random UUID hex string
|
|
|
|
:return: a random UUID (e.g. '0b98cf96d90447bda4b46f31aeb1508c')
|
|
:rtype: string
|
|
"""
|
|
return uuid.uuid4().hex
|
|
|
|
|
|
def rand_name(name='', prefix='armada'):
|
|
"""Generate a random name that includes a random number
|
|
|
|
:param str name: The name that you want to include
|
|
:param str prefix: The prefix that you want to include
|
|
:return: a random name. The format is
|
|
'<prefix>-<name>-<random number>'.
|
|
(e.g. 'prefixfoo-namebar-154876201')
|
|
:rtype: string
|
|
"""
|
|
randbits = str(random.randint(1, 0x7fffffff))
|
|
rand_name = randbits
|
|
if name:
|
|
rand_name = name + '-' + rand_name
|
|
if prefix:
|
|
rand_name = prefix + '-' + rand_name
|
|
return rand_name
|
|
|
|
|
|
def rand_bool():
|
|
"""Generate a random boolean value.
|
|
|
|
:return: a random boolean value.
|
|
:rtype: boolean
|
|
"""
|
|
return random.choice([True, False])
|
|
|
|
|
|
def rand_int(min, max):
|
|
"""Generate a random integer value between range (`min`, `max`).
|
|
|
|
:return: a random integer between the range(`min`, `max`).
|
|
:rtype: integer
|
|
"""
|
|
return random.randint(min, max)
|
|
|
|
|
|
def rand_password(length=15):
|
|
"""Generate a random password
|
|
:param int length: The length of password that you expect to set
|
|
(If it's smaller than 3, it's same as 3.)
|
|
:return: a random password. The format is
|
|
'<random upper letter>-<random number>-<random special character>
|
|
-<random ascii letters or digit characters or special symbols>'
|
|
(e.g. 'G2*ac8&lKFFgh%2')
|
|
:rtype: string
|
|
"""
|
|
upper = random.choice(string.ascii_uppercase)
|
|
ascii_char = string.ascii_letters
|
|
digits = string.digits
|
|
digit = random.choice(string.digits)
|
|
puncs = '~!@#%^&*_=+'
|
|
punc = random.choice(puncs)
|
|
seed = ascii_char + digits + puncs
|
|
pre = upper + digit + punc
|
|
password = pre + ''.join(random.choice(seed) for x in range(length - 3))
|
|
return password
|
|
|
|
|
|
def attr(**kwargs):
|
|
"""A decorator which applies the testtools attr decorator
|
|
|
|
This decorator applies the testtools.testcase.attr if it is in the list of
|
|
attributes to testtools we want to apply.
|
|
"""
|
|
|
|
def decorator(f):
|
|
if 'type' in kwargs and isinstance(kwargs['type'], str):
|
|
f = testtools.testcase.attr(kwargs['type'])(f)
|
|
elif 'type' in kwargs and isinstance(kwargs['type'], list):
|
|
for attr in kwargs['type']:
|
|
f = testtools.testcase.attr(attr)(f)
|
|
return f
|
|
|
|
return decorator
|
|
|
|
|
|
class AttrDict(dict):
|
|
"""Allows defining objects with attributes without defining a class
|
|
|
|
"""
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(AttrDict, self).__init__(*args, **kwargs)
|
|
self.__dict__ = self
|