Add license validation to the config validation check

Should prevent a customer from accidentally saving a config that violates their license

Fixes https://jira.coreos.com/browse/QS-97
This commit is contained in:
Joseph Schorr 2017-12-19 13:44:08 -05:00
parent 024c183f67
commit 72bfebdb60
5 changed files with 75 additions and 0 deletions

View file

@ -19,6 +19,8 @@ angular.module("core-config-setup", ['angularFileUpload'])
$scope.GITHOST_REGEX = '^https?://([a-zA-Z0-9]+\.?\/?)+$';
$scope.SERVICES = [
{'id': 'license', 'title': 'License'},
{'id': 'redis', 'title': 'Redis'},
{'id': 'registry-storage', 'title': 'Registry Storage'},

View file

@ -3,6 +3,7 @@ import logging
from auth.auth_context import get_authenticated_user
from data.users import LDAP_CERT_FILENAME
from util.config.validators.validate_license import LicenseValidator
from util.config.validators.validate_database import DatabaseValidator
from util.config.validators.validate_redis import RedisValidator
from util.config.validators.validate_storage import StorageValidator
@ -40,6 +41,7 @@ CONFIG_FILENAMES = (SSL_FILENAMES + DB_SSL_FILENAMES + JWT_FILENAMES + ACI_CERT_
EXTRA_CA_DIRECTORY = 'extra_ca_certs'
VALIDATORS = {
LicenseValidator.name: LicenseValidator.validate,
DatabaseValidator.name: DatabaseValidator.validate,
RedisValidator.name: RedisValidator.validate,
StorageValidator.name: StorageValidator.validate,

View file

@ -0,0 +1,48 @@
import pytest
from mock import patch
from util.config.validators import ConfigValidationException
from util.config.validators.validate_license import LicenseValidator
from util.morecollections import AttrDict
from util.license import License, QUAY_DEPLOYMENTS_ENTITLEMENT, QUAY_ENTITLEMENT
from test.fixtures import *
@pytest.mark.parametrize('deployments, allowed_deployments', [
(1, 1),
(3, 3),
(3, 2),
(3, 1),
])
def test_too_many_storage_engines(deployments, allowed_deployments, app):
def get_license():
decoded = {
'expirationDate': '2157-12-1',
'subscriptions': {
'someSubscription': {
'serviceEnd': '2157-12-1',
'durationPeriod': 'yearly',
'entitlements': {
QUAY_ENTITLEMENT: 1,
QUAY_DEPLOYMENTS_ENTITLEMENT: allowed_deployments,
},
},
},
}
return License(decoded)
storage_configs = [(str(i), {}) for i in range(0, deployments)]
with patch('app.config_provider.get_license', get_license):
validator = LicenseValidator()
if allowed_deployments < deployments:
with pytest.raises(ConfigValidationException):
validator.validate({
'DISTRIBUTED_STORAGE_CONFIG': storage_configs,
}, None, None)
else:
validator.validate({
'DISTRIBUTED_STORAGE_CONFIG': storage_configs,
}, None, None)

View file

@ -0,0 +1,19 @@
from app import config_provider
from util.config.validators import BaseValidator, ConfigValidationException
from util.license import LicenseDecodeError, EntitlementStatus
class LicenseValidator(BaseValidator):
name = "license"
@classmethod
def validate(cls, config, user, user_password):
try:
decoded_license = config_provider.get_license()
except LicenseDecodeError as le:
raise ConfigValidationException('Could not decode license: %s' % le.message)
results = decoded_license.validate(config)
all_met = all(result.is_met() for result in results)
if not all_met:
reason = [result.description() for result in results if not result.is_met()]
raise ConfigValidationException('License does not match configuration: %s' % reason)

View file

@ -204,6 +204,10 @@ class EntitlementValidationResult(object):
entitlement=repr(self.entitlement),
))
def description(self):
msg = '%s requires %s: has status %s'
return msg % (self.requirement.name, self.requirement.count, self.get_status())
def as_dict(self, for_private=False):
def req_view():
return {