Skip to content

Commit

Permalink
Support INGRESS_AVAILABLE and add tests (#329)
Browse files Browse the repository at this point in the history
  • Loading branch information
huyhg authored Mar 15, 2019
1 parent a7cfcf6 commit 192967a
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 36 deletions.
16 changes: 12 additions & 4 deletions docs/schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,8 @@ It defines how this object will be handled. Each type has a different set of pro
- `STORAGE_CLASS`: The name of a pre-provisioned k8s `StorageClass`. If it does not exist, one is created.
- `STRING`: A string that needs special handling.
- `APPLICATION_UID`: The uuid of the created `Application` object.
- `ISTIO_ENABLED`: Indicates whether Istio is enabled for the deployement.
- `ISTIO_ENABLED`: Indicates whether Istio is enabled for the deployment.
- `INGRESS_AVAILABLE`: Indicates whether the cluster is detected to have Ingress support.

---

Expand Down Expand Up @@ -410,7 +411,11 @@ In the example above, manifests can reference to the password as `explicitPasswo

This boolean property receives a True value if the environment is detected to have Istio enabled, and False otherwise. The deployer and template can take this signal to adapt the deployment accordingly.

If `ISTIO_ENABLED` is not present, it is assumed Istio is NOT enabled for the deployment.
---

### type: INGRESS_AVAILABLE

This boolean property receives a True value if the cluster is detected to have Ingress controller. The deployer and template can take this signal to adapt the deployment accordingly.

---

Expand Down Expand Up @@ -475,9 +480,12 @@ x-google-marketplace:
type: OPTIONAL | REQUIRED | UNSUPPORTED
```

If this is not specified, the UI will warn the user when the app is deployed into an istio enabled environment.

Also see `ISTIO_ENABLED` property type.

#### Supported types

- `OPTIONAL`: The app works with Istio but does not require it.
- `REQUIRED`: The app requires Istio to work properly.
- `UNSUPPORTED`: The app does not support Istio.

If the compatibility with Istio is unknown, the property is omitted completely.
31 changes: 26 additions & 5 deletions marketplace/deployer_util/config_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
XTYPE_STRING = 'STRING'
XTYPE_APPLICATION_UID = 'APPLICATION_UID'
XTYPE_ISTIO_ENABLED = 'ISTIO_ENABLED'
XTYPE_INGRESS_AVAILABLE = 'INGRESS_AVAILABLE'

WIDGET_TYPES = ['help']

Expand Down Expand Up @@ -464,7 +465,6 @@ def __init__(self, name, dictionary, required):
self._service_account = None
self._storage_class = None
self._string = None
self._istio_enabled = None

if not NAME_RE.match(name):
raise InvalidSchema('Invalid property name: {}'.format(name))
Expand All @@ -488,16 +488,20 @@ def __init__(self, name, dictionary, required):
if self._x:
xt = _must_get(self._x, 'type',
'Property {} has {} without a type'.format(name, XGOOGLE))
if xt in (XTYPE_NAME, XTYPE_NAMESPACE, XTYPE_DEPLOYER_IMAGE,
XTYPE_ISTIO_ENABLED):
pass
if xt in (XTYPE_NAME, XTYPE_NAMESPACE, XTYPE_DEPLOYER_IMAGE):
_property_must_have_type(self, str)
elif xt in (XTYPE_ISTIO_ENABLED, XTYPE_INGRESS_AVAILABLE):
_property_must_have_type(self, bool)
elif xt == XTYPE_APPLICATION_UID:
_property_must_have_type(self, str)
d = self._x.get('applicationUid', {})
self._application_uid = SchemaXApplicationUid(d)
elif xt == XTYPE_IMAGE:
_property_must_have_type(self, str)
d = self._x.get('image', {})
self._image = SchemaXImage(d)
elif xt == XTYPE_PASSWORD:
_property_must_have_type(self, str)
d = self._x.get('generatedPassword', {})
spec = {
'length': d.get('length', 10),
Expand All @@ -506,15 +510,19 @@ def __init__(self, name, dictionary, required):
}
self._password = SchemaXPassword(**spec)
elif xt == XTYPE_SERVICE_ACCOUNT:
_property_must_have_type(self, str)
d = self._x.get('serviceAccount', {})
self._service_account = SchemaXServiceAccount(d)
elif xt == XTYPE_STORAGE_CLASS:
_property_must_have_type(self, str)
d = self._x.get('storageClass', {})
self._storage_class = SchemaXStorageClass(d)
elif xt == XTYPE_STRING:
_property_must_have_type(self, str)
d = self._x.get('string', {})
self._string = SchemaXString(d)
elif xt == XTYPE_REPORTING_SECRET:
_property_must_have_type(self, str)
d = self._x.get('reportingSecret', {})
self._reporting_secret = SchemaXReportingSecret(d)
else:
Expand Down Expand Up @@ -758,7 +766,20 @@ def _must_get_and_apply(dictionary, key, apply_fn, error_msg):


def _must_contain(value, valid_list, error_msg):
"""Validates that value is one of valid_list. Raises InvalidSchema if valid_list does not contain the value."""
"""Validates that value in valid_list, or raises InvalidSchema."""
if value not in valid_list:
raise InvalidSchema("{}. Must be one of {}".format(error_msg,
', '.join(_ISTIO_TYPES)))


def _property_must_have_type(prop, expected_type):
if prop.type != expected_type:
readable_type = {
str: 'string',
bool: 'boolean',
int: 'integer',
float: 'float',
}.get(expected_type, expected_type.__name__)
raise InvalidSchema(
'{} x-google-marketplace type property must be of type {}'.format(
prop.xtype, readable_type))
67 changes: 66 additions & 1 deletion marketplace/deployer_util/config_helper_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@
type: boolean
x-google-marketplace:
type: ISTIO_ENABLED
ingressAvailable:
type: boolean
x-google-marketplace:
type: INGRESS_AVAILABLE
required:
- propertyString
- propertyPassword
Expand Down Expand Up @@ -115,7 +119,7 @@ def test_types_and_defaults(self):
'propertyIntegerWithDefault', 'propertyNumber',
'propertyNumberWithDefault', 'propertyBoolean',
'propertyBooleanWithDefault', 'propertyImage', 'propertyDeployerImage',
'propertyPassword', 'applicationUid', 'istioEnabled'
'propertyPassword', 'applicationUid', 'istioEnabled', 'ingressAvailable'
}, set(schema.properties))
self.assertEqual(str, schema.properties['propertyString'].type)
self.assertIsNone(schema.properties['propertyString'].default)
Expand Down Expand Up @@ -152,6 +156,11 @@ def test_types_and_defaults(self):
schema.properties['propertyPassword'].xtype)
self.assertEqual('My arbitrary <i>description</i>',
schema.form[0]['description'])
self.assertEqual(bool, schema.properties['istioEnabled'].type)
self.assertEqual('ISTIO_ENABLED', schema.properties['istioEnabled'].xtype)
self.assertEqual(bool, schema.properties['ingressAvailable'].type)
self.assertEqual('INGRESS_AVAILABLE',
schema.properties['ingressAvailable'].xtype)

def test_invalid_names(self):
self.assertRaises(
Expand All @@ -168,6 +177,62 @@ def test_valid_names(self):
type: string
""")

def test_invalid_property_types(self):
self.assertRaisesRegexp(
config_helper.InvalidSchema,
r'.*must be of type string$', lambda: config_helper.Schema.load_yaml("""
properties:
u:
type: integer
x-google-marketplace:
type: NAME
"""))
self.assertRaisesRegexp(
config_helper.InvalidSchema,
r'.*must be of type string$', lambda: config_helper.Schema.load_yaml("""
properties:
u:
type: number
x-google-marketplace:
type: NAMESPACE
"""))
self.assertRaisesRegexp(
config_helper.InvalidSchema,
r'.*must be of type string$', lambda: config_helper.Schema.load_yaml("""
properties:
u:
type: int
x-google-marketplace:
type: DEPLOYER_IMAGE
"""))
self.assertRaisesRegexp(
config_helper.InvalidSchema,
r'.*must be of type string$', lambda: config_helper.Schema.load_yaml("""
properties:
u:
type: boolean
x-google-marketplace:
type: APPLICATION_UID
"""))
self.assertRaisesRegexp(
config_helper.InvalidSchema, r'.*must be of type boolean$', lambda:
config_helper.Schema.load_yaml("""
properties:
u:
type: string
x-google-marketplace:
type: ISTIO_ENABLED
"""))
self.assertRaisesRegexp(
config_helper.InvalidSchema, r'.*must be of type boolean$', lambda:
config_helper.Schema.load_yaml("""
properties:
u:
type: string
x-google-marketplace:
type: INGRESS_AVAILABLE
"""))

def test_required(self):
schema = config_helper.Schema.load_yaml(SCHEMA)
self.assertTrue(schema.properties['propertyString'].required)
Expand Down
52 changes: 26 additions & 26 deletions marketplace/deployer_util/expand_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import yaml

import config_helper
import schema_values_common
from password import GeneratePassword

Expand Down Expand Up @@ -69,32 +70,31 @@ def expand(values_dict, schema, app_uid=''):
for k, prop in schema.properties.iteritems():
v = values_dict.get(k, None)

if v is None and prop.password:
if prop.type != str:
raise InvalidProperty(
'Property {} is expected to be of type string'.format(k))
result[k] = generate_password(prop.password)
continue

if v is None and prop.application_uid:
result[k] = app_uid or ''
generate_properties_for_appuid(prop, app_uid, generated)
continue

if v is None and prop.default is not None:
v = prop.default

if v is not None and prop.image:
if not isinstance(v, str):
raise InvalidProperty('Invalid value for IMAGE property {}: {}'.format(
k, v))
generate_properties_for_image(prop, v, generated)

if v is not None and prop.string:
if not isinstance(v, str):
raise InvalidProperty('Invalid value for STRING property {}: {}'.format(
k, v))
generate_properties_for_string(prop, v, generated)
if v is None:
if prop.password:
v = generate_password(prop.password)
elif prop.application_uid:
v = app_uid or ''
generate_properties_for_appuid(prop, app_uid, generated)
elif prop.xtype == config_helper.XTYPE_ISTIO_ENABLED:
# For backward compatibility.
v = False
elif prop.xtype == config_helper.XTYPE_INGRESS_AVAILABLE:
# For backward compatibility.
v = True
elif prop.default is not None:
v = prop.default
else: # if v is None
if prop.image:
if not isinstance(v, str):
raise InvalidProperty(
'Invalid value for IMAGE property {}: {}'.format(k, v))
generate_properties_for_image(prop, v, generated)
if prop.string:
if not isinstance(v, str):
raise InvalidProperty(
'Invalid value for STRING property {}: {}'.format(k, v))
generate_properties_for_string(prop, v, generated)

if v is not None:
result[k] = v
Expand Down
28 changes: 28 additions & 0 deletions marketplace/deployer_util/expand_config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,34 @@ def test_application_uid(self):
'application.create': True
}, result)

def test_istio_enabled_backward_compatibility(self):
schema = config_helper.Schema.load_yaml("""
applicationApiVersion: v1beta1
properties:
istioEnabled:
type: boolean
x-google-marketplace:
type: ISTIO_ENABLED
""")
result = expand_config.expand({}, schema)
self.assertEqual({'istioEnabled': False}, result)
result = expand_config.expand({'istioEnabled': True}, schema)
self.assertEqual({'istioEnabled': True}, result)

def test_ingress_available_backward_compatibility(self):
schema = config_helper.Schema.load_yaml("""
applicationApiVersion: v1beta1
properties:
ingressAvail:
type: boolean
x-google-marketplace:
type: INGRESS_AVAILABLE
""")
result = expand_config.expand({}, schema)
self.assertEqual({'ingressAvail': True}, result)
result = expand_config.expand({'ingressAvail': False}, schema)
self.assertEqual({'ingressAvail': False}, result)

def test_write_values(self):
schema = config_helper.Schema.load_yaml("""
applicationApiVersion: v1beta1
Expand Down
7 changes: 7 additions & 0 deletions marketplace/deployer_util/provision.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import yaml

import config_helper
import schema_values_common
import storage

Expand Down Expand Up @@ -83,6 +84,12 @@ def process(schema, values, deployer_image, deployer_entrypoint):
schema, prop, app_name=app_name, namespace=namespace)
props[prop.name] = value
manifests += sc_manifests
elif prop.xtype == config_helper.XTYPE_ISTIO_ENABLED:
# TODO: Really populate this value.
props[prop.name] = False
elif prop.xtype == config_helper.XTYPE_INGRESS_AVAILABLE:
# TODO: Really populate this value.
props[prop.name] = True

# Merge input and provisioned properties.
app_params = dict(list(values.iteritems()) + list(props.iteritems()))
Expand Down
8 changes: 8 additions & 0 deletions tests/marketplace/deployer_envsubst_base/full/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ properties:
type: string
x-google-marketplace:
type: REPORTING_SECRET
istioEnabled:
type: boolean
x-google-marketplace:
type: ISTIO_ENABLED
ingressAvailable:
type: boolean
x-google-marketplace:
type: INGRESS_AVAILABLE
required:
- name
- namespace
Expand Down

0 comments on commit 192967a

Please sign in to comment.