Merge remote-tracking branch 'upstream/2015.8' into 2015.8

This commit is contained in:
Rafael Uzarowski 2015-07-17 13:06:36 +02:00
commit 4dbd9ebb30
30 changed files with 562 additions and 434 deletions

View file

@ -19,6 +19,9 @@ Salt Cloud Changes
- Modified the Linode Salt Cloud driver to use Linode's native API instead of
depending on apache-libcloud or linode-python.
- When querying for VMs in ``ditigal_ocean.py``, the number of VMs to include in
a page was changed from 20 (default) to 200 to reduce the number of API calls
to Digital Ocean.
JBoss 7 State
=============

View file

@ -169,3 +169,9 @@ if sys.version_info < (2, 7):
raise subprocess.CalledProcessError(retcode, cmd, output=output)
return output
subprocess.check_output = check_output
if PY3:
import ipaddress
else:
import salt.ext.ipaddress as ipaddress

View file

@ -568,11 +568,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'aliyun',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'aliyun',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -222,11 +222,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'cloudstack',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'cloudstack',
vm_['profile']) is False:
return False
except AttributeError:
pass
salt.utils.cloud.fire_event(
'event',

View file

@ -122,7 +122,7 @@ def avail_images(call=None):
ret = {}
while fetch:
items = query(method='images', command='?page=' + str(page))
items = query(method='images', command='?page=' + str(page) + '&per_page=200')
for image in items['images']:
ret[image['id']] = {}
@ -172,7 +172,7 @@ def list_nodes(call=None):
ret = {}
while fetch:
items = query(method='droplets', command='?page=' + str(page))
items = query(method='droplets', command='?page=' + str(page) + '&per_page=200')
for node in items['droplets']:
ret[node['name']] = {
'id': node['id'],
@ -204,7 +204,7 @@ def list_nodes_full(call=None, forOutput=True):
ret = {}
while fetch:
items = query(method='droplets', command='?page=' + str(page))
items = query(method='droplets', command='?page=' + str(page) + '&per_page=200')
for node in items['droplets']:
ret[node['name']] = {}
for item in six.iterkeys(node):
@ -295,11 +295,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'digital_ocean',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'digital_ocean',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -2162,11 +2162,14 @@ def create(vm_=None, call=None):
'You cannot create an instance with -a or -f.'
)
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'ec2',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'ec2',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -2028,11 +2028,14 @@ def create(vm_=None, call=None):
)
)
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'gce',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'gce',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -82,11 +82,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'gogrid',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'gogrid',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -242,11 +242,14 @@ def create(vm_):
salt-cloud -p profile_name vm_name
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'joyent',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'joyent',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -310,11 +310,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'aws',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'aws',
vm_['profile']) is False:
return False
except AttributeError:
pass
key_filename = config.get_cloud_config_value(
'private_key', vm_, __opts__, search_global=False, default=None

View file

@ -197,11 +197,14 @@ def create(vm_):
'''
Create a single Linode VM.
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'linode',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'linode',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -399,11 +399,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'azure',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'azure',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -530,11 +530,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'nova',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'nova',
vm_['profile']) is False:
return False
except AttributeError:
pass
deploy = config.get_cloud_config_value('deploy', vm_, __opts__)
key_filename = config.get_cloud_config_value(

View file

@ -284,11 +284,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'opennebula',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'opennebula',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -593,11 +593,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'openstack',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'openstack',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -270,11 +270,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'parallels',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'parallels',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -480,11 +480,14 @@ def create(vm_):
salt-cloud -p proxmox-ubuntu vmhostname
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'proxmox',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'proxmox',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -638,11 +638,14 @@ def create(vm_):
salt-cloud -p qingcloud-ubuntu-c1m1 hostname1
salt-cloud -m /path/to/mymap.sls -P
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'qingcloud',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'qingcloud',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -181,11 +181,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'rackspace',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'rackspace',
vm_['profile']) is False:
return False
except AttributeError:
pass
deploy = config.get_cloud_config_value('deploy', vm_, __opts__)
salt.utils.cloud.fire_event(

View file

@ -190,11 +190,14 @@ def create(server_):
'''
Create a single BareMetal server from a data dict.
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'scaleway',
server_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'scaleway',
server_['profile']) is False:
return False
except AttributeError:
pass
salt.utils.cloud.fire_event(
'event',

View file

@ -234,11 +234,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'softlayer',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'softlayer',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -207,11 +207,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'softlayer_hw',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'softlayer_hw',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -2038,11 +2038,14 @@ def create(vm_):
salt-cloud -p vmware-centos6.5 vmname
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'vmware',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'vmware',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -228,11 +228,14 @@ def create(vm_):
'''
Create a single VM from a data dict
'''
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'vsphere',
vm_['profile']) is False:
return False
try:
# Check for required profile parameters before sending any API calls.
if config.is_profile_configured(__opts__,
__active_provider_name__ or 'vsphere',
vm_['profile']) is False:
return False
except AttributeError:
pass
# Since using "provider: <provider-engine>" is deprecated, alias provider
# to use driver: "driver: <provider-engine>"

View file

@ -2395,7 +2395,8 @@ def is_profile_configured(opts, provider, profile_name):
alias, driver = provider.split(':')
# Most drivers need a size, but some do not.
non_size_drivers = ['parallels', 'softlayer', 'softlayer_hw']
non_size_drivers = ['opennebula', 'parallels', 'softlayer', 'softlayer_hw',
'vmware', 'vsphere']
if driver not in non_size_drivers:
required_keys.append('size')

View file

@ -687,23 +687,27 @@ class Key(object):
if match.startswith('acc'):
ret[os.path.basename(acc)] = []
for fn_ in salt.utils.isorted(os.listdir(acc)):
if os.path.isfile(os.path.join(acc, fn_)):
ret[os.path.basename(acc)].append(fn_)
if not fn_.startswith('.'):
if os.path.isfile(os.path.join(acc, fn_)):
ret[os.path.basename(acc)].append(fn_)
elif match.startswith('pre') or match.startswith('un'):
ret[os.path.basename(pre)] = []
for fn_ in salt.utils.isorted(os.listdir(pre)):
if os.path.isfile(os.path.join(pre, fn_)):
ret[os.path.basename(pre)].append(fn_)
if not fn_.startswith('.'):
if os.path.isfile(os.path.join(pre, fn_)):
ret[os.path.basename(pre)].append(fn_)
elif match.startswith('rej'):
ret[os.path.basename(rej)] = []
for fn_ in salt.utils.isorted(os.listdir(rej)):
if os.path.isfile(os.path.join(rej, fn_)):
ret[os.path.basename(rej)].append(fn_)
if not fn_.startswith('.'):
if os.path.isfile(os.path.join(rej, fn_)):
ret[os.path.basename(rej)].append(fn_)
elif match.startswith('den'):
ret[os.path.basename(den)] = []
for fn_ in salt.utils.isorted(os.listdir(den)):
if os.path.isfile(os.path.join(den, fn_)):
ret[os.path.basename(den)].append(fn_)
if not fn_.startswith('.'):
if os.path.isfile(os.path.join(den, fn_)):
ret[os.path.basename(den)].append(fn_)
elif match.startswith('all'):
return self.all_keys()
return ret

View file

@ -6,12 +6,17 @@ Scan a netmask or ipaddr for open ssh ports
# Import python libs
from __future__ import absolute_import
import socket
import logging
# Import salt libs
import salt.utils.network
import salt.ext.ipaddress as ipaddress
from salt._compat import ipaddress
# Import 3rd-party libs
from salt.ext.six.moves import map # pylint: disable=import-error,redefined-builtin
log = logging.getLogger(__name__)
def targets(tgt, tgt_type='glob', **kwargs):
'''
@ -49,11 +54,14 @@ class RosterMatcher(object):
except ValueError:
pass
for addr in addrs:
addr = str(addr)
log.trace('Scanning host: {0}'.format(addr))
for port in ports:
log.trace('Scanning port: {0}'.format(port))
try:
sock = salt.utils.network.get_socket(addr, socket.SOCK_STREAM)
sock.settimeout(float(__opts__['ssh_scan_timeout']))
sock.connect((str(addr), port))
sock.connect((addr, port))
sock.shutdown(socket.SHUT_RDWR)
sock.close()
ret[addr] = {'host': addr, 'port': port}

View file

@ -172,7 +172,10 @@ class CkMinions(object):
'''
pki_dir = os.path.join(self.opts['pki_dir'], self.acc)
try:
files = os.listdir(pki_dir)
files = []
for fn_ in salt.utils.isorted(os.listdir(pki_dir)):
if not fn_.startswith('.') and os.path.isfile(os.path.join(pki_dir, fn_)):
files.append(fn_)
return fnmatch.filter(files, expr)
except OSError:
return []
@ -194,7 +197,10 @@ class CkMinions(object):
Return the minions found by looking via regular expressions
'''
try:
minions = os.listdir(os.path.join(self.opts['pki_dir'], self.acc))
minions = []
for fn_ in salt.utils.isorted(os.listdir(os.path.join(self.opts['pki_dir'], self.acc))):
if not fn_.startswith('.') and os.path.isfile(os.path.join(self.opts['pki_dir'], self.acc, fn_)):
minions.append(fn_)
reg = re.compile(expr)
return [m for m in minions if reg.match(m)]
except OSError:
@ -213,9 +219,11 @@ class CkMinions(object):
cache_enabled = self.opts.get('minion_data_cache', False)
if greedy:
minions = set(
os.listdir(os.path.join(self.opts['pki_dir'], self.acc))
)
mlist = []
for fn_ in salt.utils.isorted(os.listdir(os.path.join(self.opts['pki_dir'], self.acc))):
if not fn_.startswith('.') and os.path.isfile(os.path.join(self.opts['pki_dir'], self.acc, fn_)):
mlist.append(fn_)
minions = set(mlist)
elif cache_enabled:
minions = os.listdir(os.path.join(self.opts['cachedir'], 'minions'))
else:
@ -293,9 +301,11 @@ class CkMinions(object):
cache_enabled = self.opts.get('minion_data_cache', False)
if greedy:
minions = set(
os.listdir(os.path.join(self.opts['pki_dir'], self.acc))
)
mlist = []
for fn_ in salt.utils.isorted(os.listdir(os.path.join(self.opts['pki_dir'], self.acc))):
if not fn_.startswith('.') and os.path.isfile(os.path.join(self.opts['pki_dir'], self.acc, fn_)):
mlist.append(fn_)
minions = set(mlist)
elif cache_enabled:
minions = os.listdir(os.path.join(self.opts['cachedir'], 'minions'))
else:
@ -364,7 +374,11 @@ class CkMinions(object):
)
cache_enabled = self.opts.get('minion_data_cache', False)
if greedy:
return os.listdir(os.path.join(self.opts['pki_dir'], self.acc))
mlist = []
for fn_ in salt.utils.isorted(os.listdir(os.path.join(self.opts['pki_dir'], self.acc))):
if not fn_.startswith('.') and os.path.isfile(os.path.join(self.opts['pki_dir'], self.acc, fn_)):
mlist.append(fn_)
return mlist
elif cache_enabled:
return os.listdir(os.path.join(self.opts['cachedir'], 'minions'))
else:
@ -393,9 +407,11 @@ class CkMinions(object):
if not isinstance(expr, six.string_types) and not isinstance(expr, (list, tuple)):
log.error('Compound target that is neither string, list nor tuple')
return []
minions = set(
os.listdir(os.path.join(self.opts['pki_dir'], self.acc))
)
mlist = []
for fn_ in salt.utils.isorted(os.listdir(os.path.join(self.opts['pki_dir'], self.acc))):
if not fn_.startswith('.') and os.path.isfile(os.path.join(self.opts['pki_dir'], self.acc, fn_)):
mlist.append(fn_)
minions = set(mlist)
log.debug('minions: {0}'.format(minions))
if self.opts.get('minion_data_cache', False):
@ -565,7 +581,11 @@ class CkMinions(object):
'''
Return a list of all minions that have auth'd
'''
return os.listdir(os.path.join(self.opts['pki_dir'], self.acc))
mlist = []
for fn_ in salt.utils.isorted(os.listdir(os.path.join(self.opts['pki_dir'], self.acc))):
if not fn_.startswith('.') and os.path.isfile(os.path.join(self.opts['pki_dir'], self.acc, fn_)):
mlist.append(fn_)
return mlist
def check_minions(self,
expr,

View file

@ -3,7 +3,7 @@
:codeauthor: :email:`Pedro Algarvio (pedro@algarvio.me)`
salt.utils.config
salt.utils.schema
~~~~~~~~~~~~~~~~~
Object Oriented Configuration - JSON Schema compatible generator
@ -14,25 +14,25 @@
A configuration document or configuration document section is defined using the
py:class:`Configuration`, the configuration items are defined by any of the subclasses
of py:class:`BaseConfigItem` as attributes of a subclass of py:class:`Configuration` class.
py:class:`Schema`, the configuration items are defined by any of the subclasses
of py:class:`BaseSchemaItem` as attributes of a subclass of py:class:`Schema` class.
As an example:
.. code-block:: python
class HostConfig(Configuration):
class HostConfig(Schema):
title = 'Host Configuration'
description = 'This is the host configuration'
host = StringConfig(
host = StringItem(
'Host',
'The looong host description',
default=None,
minimum=1
)
port = NumberConfig(
port = NumberItem(
description='The port number',
default=80,
required=False,
@ -136,18 +136,18 @@
.. code-block:: python
class LoggingConfig(Configuration):
class LoggingConfig(Schema):
title = 'Logging Configuration'
description = 'This is the logging configuration'
log_level = StringConfig(
log_level = StringItem(
'Logging Level',
'The logging level',
default='debug',
minimum=1
)
class MyConfig(Configuration):
class MyConfig(Schema):
title = 'My Config'
description = 'This my configuration'
@ -258,7 +258,7 @@
.. code-block:: python
class MyConfig(Configuration):
class MyConfig(Schema):
title = 'My Config'
description = 'This my configuration'
@ -395,7 +395,7 @@ NullSentinel.__new__ = staticmethod(_failing_new)
del _failing_new
class ConfigurationMeta(six.with_metaclass(Prepareable, type)):
class SchemaMeta(six.with_metaclass(Prepareable, type)):
@classmethod
def __prepare__(mcs, name, bases):
@ -455,7 +455,7 @@ class ConfigurationMeta(six.with_metaclass(Prepareable, type)):
return instance
class BaseConfigItemMeta(six.with_metaclass(Prepareable, type)):
class BaseSchemaItemMeta(six.with_metaclass(Prepareable, type)):
'''
Config item metaclass to "tag" the class as a configuration item
'''
@ -512,7 +512,7 @@ class BaseConfigItemMeta(six.with_metaclass(Prepareable, type)):
return instance
class Configuration(six.with_metaclass(ConfigurationMeta, object)):
class Schema(six.with_metaclass(SchemaMeta, object)):
'''
Configuration definition class
'''
@ -582,7 +582,8 @@ class Configuration(six.with_metaclass(ConfigurationMeta, object)):
if name not in ordering:
ordering.append(name)
serialized['properties'] = properties
if properties:
serialized['properties'] = properties
# Update the serialized object with any items to include after properties
serialized.update(after_items_update)
@ -617,7 +618,7 @@ class Configuration(six.with_metaclass(ConfigurationMeta, object)):
# raise NotImplementedError
class BaseItem(six.with_metaclass(BaseConfigItemMeta, object)):
class SchemaItem(six.with_metaclass(BaseSchemaItemMeta, object)):
'''
Base configuration items class.
@ -683,7 +684,7 @@ class BaseItem(six.with_metaclass(BaseConfigItemMeta, object)):
raise NotImplementedError
class BaseConfigItem(BaseItem):
class BaseSchemaItem(SchemaItem):
'''
Base configuration items class.
@ -692,7 +693,7 @@ class BaseConfigItem(BaseItem):
# Let's define description as a class attribute, this will allow a custom configuration
# item to do something like:
# class MyCustomConfig(StringConfig):
# class MyCustomConfig(StringItem):
# '''
# This is my custom config, blah, blah, blah
# '''
@ -729,7 +730,7 @@ class BaseConfigItem(BaseItem):
self.enum = enum
if enumNames is not None:
self.enumNames = enumNames
super(BaseConfigItem, self).__init__(**kwargs)
super(BaseSchemaItem, self).__init__(**kwargs)
def __validate_attributes__(self):
if self.enum is not None:
@ -811,11 +812,11 @@ class BaseConfigItem(BaseItem):
# return output + '\n'
class BooleanConfig(BaseConfigItem):
class BooleanItem(BaseSchemaItem):
__type__ = 'boolean'
class StringConfig(BaseConfigItem):
class StringItem(BaseSchemaItem):
'''
A string configuration field
'''
@ -867,14 +868,14 @@ class StringConfig(BaseConfigItem):
self.min_length = min_length
if max_length is not None:
self.max_length = max_length
super(StringConfig, self).__init__(**kwargs)
super(StringItem, self).__init__(**kwargs)
def __validate_attributes__(self):
if self.format is None and self.__format__ is not None:
self.format = self.__format__
class EMailConfig(StringConfig):
class EMailItem(StringItem):
'''
An internet email address, see `RFC 5322, section 3.4.1`__.
@ -883,7 +884,7 @@ class EMailConfig(StringConfig):
__format__ = 'email'
class IPv4Config(StringConfig):
class IPv4Item(StringItem):
'''
An IPv4 address configuration field, according to dotted-quad ABNF syntax as defined in
`RFC 2673, section 3.2`__.
@ -893,7 +894,7 @@ class IPv4Config(StringConfig):
__format__ = 'ipv4'
class IPv6Config(StringConfig):
class IPv6Item(StringItem):
'''
An IPv6 address configuration field, as defined in `RFC 2373, section 2.2`__.
@ -902,7 +903,7 @@ class IPv6Config(StringConfig):
__format__ = 'ipv6'
class HostnameConfig(StringConfig):
class HostnameItem(StringItem):
'''
An Internet host name configuration field, see `RFC 1034, section 3.1`__.
@ -911,7 +912,7 @@ class HostnameConfig(StringConfig):
__format__ = 'hostname'
class DateTimeConfig(StringConfig):
class DateTimeItem(StringItem):
'''
An ISO 8601 formatted date-time configuration field, as defined by `RFC 3339, section 5.6`__.
@ -920,7 +921,7 @@ class DateTimeConfig(StringConfig):
__format__ = 'date-time'
class UriConfig(StringConfig):
class UriItem(StringItem):
'''
A universal resource identifier (URI) configuration field, according to `RFC3986`__.
@ -929,14 +930,14 @@ class UriConfig(StringConfig):
__format__ = 'uri'
class SecretConfig(StringConfig):
class SecretItem(StringItem):
'''
A string configuration field containing a secret, for example, passwords, API keys, etc
'''
__format__ = 'secret'
class NumberConfig(BaseConfigItem):
class NumberItem(BaseSchemaItem):
__type__ = 'number'
@ -992,14 +993,14 @@ class NumberConfig(BaseConfigItem):
self.maximum = maximum
if exclusive_maximum is not None:
self.exclusive_maximum = exclusive_maximum
super(NumberConfig, self).__init__(**kwargs)
super(NumberItem, self).__init__(**kwargs)
class IntegerConfig(NumberConfig):
class IntegerItem(NumberItem):
__type__ = 'integer'
class ArrayConfig(BaseConfigItem):
class ArrayItem(BaseSchemaItem):
__type__ = 'array'
__serialize_attr_aliases__ = {
@ -1036,8 +1037,8 @@ class ArrayConfig(BaseConfigItem):
A list(list, tuple, set) of valid choices.
:param items:
Either of the following:
* :class:`BaseConfigItem` -- all items of the array must match the field schema;
* a list or a tuple of :class:`fields <.BaseConfigItem>` -- all items of the array must be
* :class:`BaseSchemaItem` -- all items of the array must match the field schema;
* a list or a tuple of :class:`fields <.BaseSchemaItem>` -- all items of the array must be
valid according to the field schema at the corresponding index (tuple typing);
:param min_items:
Minimum length of the array
@ -1049,7 +1050,7 @@ class ArrayConfig(BaseConfigItem):
If the value of ``items`` is a list or a tuple, and the array length is larger than
the number of fields in ``items``, then the additional items are described
by the :class:`.BaseField` passed using this argument.
:type additional_items: bool or :class:`.BaseConfigItem`
:type additional_items: bool or :class:`.BaseSchemaItem`
'''
if items is not None:
self.items = items
@ -1061,7 +1062,7 @@ class ArrayConfig(BaseConfigItem):
self.unique_items = unique_items
if additional_items is not None:
self.additional_items = additional_items
super(ArrayConfig, self).__init__(**kwargs)
super(ArrayItem, self).__init__(**kwargs)
def __validate_attributes__(self):
if not self.items:
@ -1070,22 +1071,22 @@ class ArrayConfig(BaseConfigItem):
)
if isinstance(self.items, (list, tuple)):
for item in self.items:
if not isinstance(item, (Configuration, BaseItem)):
if not isinstance(item, (Schema, SchemaItem)):
raise RuntimeError(
'All items passed in the item argument tuple/list must be '
'a subclass of Configuration, BaseItem or BaseConfigItem, '
'a subclass of Schema, SchemaItem or BaseSchemaItem, '
'not {0}'.format(type(item))
)
elif not isinstance(self.items, (Configuration, BaseItem)):
elif not isinstance(self.items, (Schema, SchemaItem)):
raise RuntimeError(
'The items argument passed must be a subclass of '
'Configuration, BaseItem or BaseConfigItem, not '
'Schema, SchemaItem or BaseSchemaItem, not '
'{0}'.format(type(self.items))
)
def __get_items__(self):
if isinstance(self.items, (Configuration, BaseItem)):
# This is either a Configuration or a Basetem, return it in it's
if isinstance(self.items, (Schema, SchemaItem)):
# This is either a Schema or a Basetem, return it in it's
# serialized form
return self.items.serialize()
if isinstance(self.items, (tuple, list)):
@ -1095,7 +1096,7 @@ class ArrayConfig(BaseConfigItem):
return items
class DictConfig(BaseConfigItem):
class DictItem(BaseSchemaItem):
__type__ = 'object'
@ -1141,12 +1142,12 @@ class DictConfig(BaseConfigItem):
A dictionary whose keys are regular expressions (ECMA 262).
Properties match against these regular expressions, and for any that match,
the property is described by the corresponding field schema.
:type pattern_properties: dict[str -> :class:`.Configuration` or
:class:`.BaseItem` or :class:`.BaseItemConfig`]
:type pattern_properties: dict[str -> :class:`.Schema` or
:class:`.SchemaItem` or :class:`.BaseSchemaItem`]
:param additional_properties:
Describes properties that are not described by the ``properties`` or ``pattern_properties``.
:type additional_properties: bool or :class:`.Configuration` or :class:`.BaseItem`
or :class:`.BaseItemConfig`
:type additional_properties: bool or :class:`.Schema` or :class:`.SchemaItem`
or :class:`.BaseSchemaItem`
:param min_properties:
A minimum number of properties.
:type min_properties: int
@ -1164,7 +1165,7 @@ class DictConfig(BaseConfigItem):
self.min_properties = min_properties
if max_properties is not None:
self.max_properties = max_properties
super(DictConfig, self).__init__(**kwargs)
super(DictItem, self).__init__(**kwargs)
def __validate_attributes__(self):
if not self.properties and not self.pattern_properties:
@ -1172,18 +1173,19 @@ class DictConfig(BaseConfigItem):
'One of properties or pattern properties must be passed'
)
if self.properties is not None:
if not isinstance(self.properties, dict):
if not isinstance(self.properties, (Schema, dict)):
raise RuntimeError(
'The passed properties must be passed as a dict not '
'\'{0}\''.format(type(self.properties))
'The passed properties must be passed as a dict or '
' a Schema not \'{0}\''.format(type(self.properties))
)
for key, prop in self.properties.items():
if not isinstance(prop, (Configuration, BaseItem)):
raise RuntimeError(
'The passed property who\'s key is \'{0}\' must be of type '
'Configuration, BaseItem or BaseConfigItem, not '
'\'{1}\''.format(key, type(prop))
)
if not isinstance(self.properties, Schema):
for key, prop in self.properties.items():
if not isinstance(prop, (Schema, SchemaItem)):
raise RuntimeError(
'The passed property who\'s key is \'{0}\' must be of type '
'Schema, SchemaItem or BaseSchemaItem, not '
'\'{1}\''.format(key, type(prop))
)
if self.pattern_properties is not None:
if not isinstance(self.pattern_properties, dict):
raise RuntimeError(
@ -1191,17 +1193,17 @@ class DictConfig(BaseConfigItem):
'not \'{0}\''.format(type(self.pattern_properties))
)
for key, prop in self.pattern_properties.items():
if not isinstance(prop, (Configuration, BaseItem)):
if not isinstance(prop, (Schema, SchemaItem)):
raise RuntimeError(
'The passed pattern_property who\'s key is \'{0}\' must '
'be of type Configuration, BaseItem or BaseConfigItem, '
'be of type Schema, SchemaItem or BaseSchemaItem, '
'not \'{1}\''.format(key, type(prop))
)
if self.additional_properties is not None:
if not isinstance(self.additional_properties, (bool, Configuration, BaseItem)):
if not isinstance(self.additional_properties, (bool, Schema, SchemaItem)):
raise RuntimeError(
'The passed additional_properties must be of type bool, '
'Configuration, BaseItem or BaseConfigItem, not \'{0}\''.format(
'Schema, SchemaItem or BaseSchemaItem, not \'{0}\''.format(
type(self.pattern_properties)
)
)
@ -1209,6 +1211,8 @@ class DictConfig(BaseConfigItem):
def __get_properties__(self):
if self.properties is None:
return
if isinstance(self.properties, Schema):
return self.properties.serialize()['properties']
properties = OrderedDict()
for key, prop in self.properties.items():
properties[key] = prop.serialize()
@ -1229,8 +1233,12 @@ class DictConfig(BaseConfigItem):
return self.additional_properties
return self.additional_properties.serialize()
def __call__(self, flatten=False):
self.__flatten__ = flatten
return self
class RequirementsItem(BaseItem):
class RequirementsItem(SchemaItem):
__type__ = 'object'
requirements = None
@ -1245,37 +1253,42 @@ class RequirementsItem(BaseItem):
raise RuntimeError(
'The passed requirements must not be empty'
)
if not isinstance(self.requirements, (Configuration, list, tuple, set)):
if not isinstance(self.requirements, (Schema, SchemaItem, list, tuple, set)):
raise RuntimeError(
'The passed requirements must be passed as a list, tuple, '
'set or Configuration, not \'{0}\''.format(self.requirements)
'set SchemaItem, BaseSchemaItem or Schema, not \'{0}\''.format(self.requirements)
)
if not isinstance(self.requirements, Configuration):
if not isinstance(self.requirements, (SchemaItem, Schema)):
if not isinstance(self.requirements, list):
self.requirements = list(self.requirements)
for idx, item in enumerate(self.requirements):
if not isinstance(item, (six.string_types, Configuration)):
if not isinstance(item, (six.string_types, (SchemaItem, Schema))):
raise RuntimeError(
'The passed requirement at the {0} index must be of type '
'str or Configuration, not \'{1}\''.format(idx, type(item))
'str or Schema, not \'{1}\''.format(idx, type(item))
)
def serialize(self):
if isinstance(self.requirements, Configuration):
if isinstance(self.requirements, Schema):
requirements = self.requirements.serialize()['required']
elif isinstance(self.requirements, SchemaItem):
requirements = self.requirements.serialize()
else:
requirements = []
for requirement in self.requirements:
if isinstance(requirement, Configuration):
if isinstance(requirement, Schema):
requirements.extend(requirement.serialize()['required'])
continue
if isinstance(requirement, SchemaItem):
requirements.append(requirement.serialize())
continue
requirements.append(requirement)
return {'required': requirements}
class OneOfConfig(BaseItem):
class OneOfItem(SchemaItem):
__type__ = 'oneOf'
@ -1284,7 +1297,7 @@ class OneOfConfig(BaseItem):
def __init__(self, items=None):
if items is not None:
self.items = items
super(OneOfConfig, self).__init__()
super(OneOfItem, self).__init__()
def __validate_attributes__(self):
if not self.items:
@ -1297,10 +1310,10 @@ class OneOfConfig(BaseItem):
'\'{0}\''.format(type(self.items))
)
for idx, item in enumerate(self.items):
if not isinstance(item, (Configuration, BaseItem)):
if not isinstance(item, (Schema, SchemaItem)):
raise RuntimeError(
'The passed item at the {0} index must be of type '
'Configuration, BaseItem or BaseConfigItem, not '
'Schema, SchemaItem or BaseSchemaItem, not '
'\'{1}\''.format(idx, type(item))
)
if not isinstance(self.items, list):
@ -1314,17 +1327,17 @@ class OneOfConfig(BaseItem):
return {self.__type__: [i.serialize() for i in self.items]}
class AnyOfConfig(OneOfConfig):
class AnyOfItem(OneOfItem):
__type__ = 'anyOf'
class AllOfConfig(OneOfConfig):
class AllOfItem(OneOfItem):
__type__ = 'allOf'
class NotConfig(BaseItem):
class NotItem(SchemaItem):
__type__ = 'not'
@ -1333,18 +1346,25 @@ class NotConfig(BaseItem):
def __init__(self, item=None):
if item is not None:
self.item = item
super(NotConfig, self).__init__()
super(NotItem, self).__init__()
def __validate_attributes__(self):
if not self.item:
raise RuntimeError(
'An item must be passed'
)
if not isinstance(self.item, (Configuration, BaseItem)):
if not isinstance(self.item, (Schema, SchemaItem)):
raise RuntimeError(
'The passed item be of type Configuration, BaseItem or '
'BaseConfigItem, not \'{1}\''.format(type(self.item))
'The passed item be of type Schema, SchemaItem or '
'BaseSchemaItem, not \'{1}\''.format(type(self.item))
)
def serialize(self):
return {self.__type__: self.item.serialize()}
# ----- Custom Preconfigured Configs -------------------------------------------------------------------------------->
class PortItem(IntegerItem):
minimum = 0 # yes, 0 is a valid port number
maximum = 65535
# <---- Custom Preconfigured Configs ---------------------------------------------------------------------------------

File diff suppressed because it is too large Load diff