Merge "remove vmware"

This commit is contained in:
Jenkins 2017-02-21 13:06:39 +00:00 committed by Gerrit Code Review
commit 3448243ba3
33 changed files with 91 additions and 2596 deletions

View File

@ -38,7 +38,6 @@ from nailgun.api.v1.validators.cluster import ClusterAttributesValidator
from nailgun.api.v1.validators.cluster import ClusterChangesValidator
from nailgun.api.v1.validators.cluster import ClusterStopDeploymentValidator
from nailgun.api.v1.validators.cluster import ClusterValidator
from nailgun.api.v1.validators.cluster import VmwareAttributesValidator
from nailgun.api.v1.validators.extension import ExtensionValidator
from nailgun import errors
@ -435,120 +434,6 @@ class ClusterOwnDeploymentTasksHandler(BaseHandler):
return tasks
class VmwareAttributesHandler(BaseHandler):
"""Vmware attributes handler"""
fields = (
"editable",
)
validator = VmwareAttributesValidator
@handle_errors
@validate
@serialize
def GET(self, cluster_id):
""":returns: JSONized Cluster vmware attributes.
:http: * 200 (OK)
* 400 (cluster doesn't accept vmware configuration)
* 404 (cluster not found in db |
cluster has no vmware attributes)
"""
cluster = self.get_object_or_404(
objects.Cluster, cluster_id,
log_404=(
"error",
"There is no cluster "
"with id '{0}' in DB.".format(cluster_id)
)
)
if not objects.Cluster.is_vmware_enabled(cluster):
raise self.http(400, "Cluster doesn't support vmware "
"configuration")
attributes = objects.Cluster.get_vmware_attributes(cluster)
if not attributes:
raise self.http(404, "No vmware attributes found")
return self.render(attributes)
@handle_errors
@validate
@serialize
def PUT(self, cluster_id):
""":returns: JSONized Cluster vmware attributes.
:http: * 200 (OK)
* 400 (wrong attributes data specified |
cluster doesn't accept vmware configuration)
* 403 (attributes can't be changed)
* 404 (cluster not found in db |
cluster has no vmware attributes)
"""
cluster = self.get_object_or_404(
objects.Cluster, cluster_id,
log_404=(
"error",
"There is no cluster "
"with id '{0}' in DB.".format(cluster_id)
)
)
if not objects.Cluster.is_vmware_enabled(cluster):
raise self.http(400, "Cluster doesn't support vmware "
"configuration")
attributes = objects.Cluster.get_vmware_attributes(cluster)
if not attributes:
raise self.http(404, "No vmware attributes found")
if cluster.is_locked and \
not objects.Cluster.has_compute_vmware_changes(cluster):
raise self.http(403, "Environment attributes can't be changed "
"after or during deployment.")
data = self.checked_data(instance=attributes)
attributes = objects.Cluster.update_vmware_attributes(cluster, data)
return {"editable": attributes}
class VmwareAttributesDefaultsHandler(BaseHandler):
"""Vmware default attributes handler"""
@handle_errors
@validate
@serialize
def GET(self, cluster_id):
""":returns: JSONized default Cluster vmware attributes.
:http: * 200 (OK)
* 400 (cluster doesn't accept vmware configuration)
* 404 (cluster not found in db)
"""
cluster = self.get_object_or_404(
objects.Cluster, cluster_id,
log_404=(
"error",
"There is no cluster "
"with id '{0}' in DB.".format(cluster_id)
)
)
if not objects.Cluster.is_vmware_enabled(cluster):
raise self.http(400, "Cluster doesn't support vmware "
"configuration")
attributes = objects.Cluster.get_default_vmware_attributes(cluster)
return {"editable": attributes}
class ClusterDeploymentGraphHandler(RelatedDeploymentGraphHandler):
"""Cluster Handler for deployment graph configuration."""
related = objects.Cluster
class ClusterDeploymentGraphCollectionHandler(
RelatedDeploymentGraphCollectionHandler):
"""Cluster Handler for deployment graphs configuration."""
@ -618,3 +503,9 @@ class ClusterExtensionsHandler(BaseHandler):
remove_extensions_from_object(cluster, data)
raise self.http(204)
class ClusterDeploymentGraphHandler(RelatedDeploymentGraphHandler):
"""Cluster Handler for deployment graph configuration."""
related = objects.Cluster

View File

@ -44,8 +44,6 @@ from nailgun.api.v1.handlers.cluster import \
ClusterReleaseDeploymentTasksHandler
from nailgun.api.v1.handlers.cluster import ClusterResetHandler
from nailgun.api.v1.handlers.cluster import ClusterStopDeploymentHandler
from nailgun.api.v1.handlers.cluster import VmwareAttributesDefaultsHandler
from nailgun.api.v1.handlers.cluster import VmwareAttributesHandler
from nailgun.api.v1.handlers.component import ComponentCollectionHandler
from nailgun.api.v1.handlers.cluster_plugin_link \
@ -270,11 +268,6 @@ urls = (
r'/clusters/(?P<cluster_id>\d+)/unassignment/?$',
NodeUnassignmentHandler,
r'/clusters/(?P<cluster_id>\d+)/vmware_attributes/?$',
VmwareAttributesHandler,
r'/clusters/(?P<cluster_id>\d+)/vmware_attributes/defaults/?$',
VmwareAttributesDefaultsHandler,
r'/clusters/(?P<cluster_id>\d+)/plugin_links/?$',
ClusterPluginLinkCollectionHandler,
r'/clusters/(?P<cluster_id>\d+)/plugin_links/(?P<obj_id>\d+)/?$',

View File

@ -297,265 +297,3 @@ class ClusterStopDeploymentValidator(base.BaseDefferedTaskValidator):
raise errors.CannotBeStopped('Current deployment process is '
'running on a pre-deployed cluster '
'that does not support LCM.')
class VmwareAttributesValidator(base.BasicValidator):
single_schema = cluster_schema.vmware_attributes_schema
@staticmethod
def _get_target_node_id(nova_compute_data):
return nova_compute_data['target_node']['current']['id']
@classmethod
def _validate_updated_attributes(cls, attributes, instance):
"""Validate that attributes contains changes only for allowed fields.
:param attributes: new vmware attribute settings for db instance
:param instance: nailgun.db.sqlalchemy.models.VmwareAttributes instance
"""
metadata = instance.editable.get('metadata', {})
db_editable_attributes = instance.editable.get('value', {})
new_editable_attributes = attributes.get('editable', {}).get('value')
for attribute_metadata in metadata:
if attribute_metadata.get('type') == 'array':
attribute_name = attribute_metadata['name']
cls._check_attribute(
attribute_metadata,
db_editable_attributes.get(attribute_name),
new_editable_attributes.get(attribute_name)
)
else:
cls._check_attribute(
attribute_metadata,
db_editable_attributes,
new_editable_attributes
)
@classmethod
def _check_attribute(cls, metadata, attributes, new_attributes):
"""Check new_attributes is equal with attributes except editable fields
:param metadata: dict describes structure and properties of attributes
:param attributes: attributes which is the basis for comparison
:param new_attributes: attributes with modifications to check
"""
if type(attributes) != type(new_attributes):
raise errors.InvalidData(
"Value type of '{0}' attribute couldn't be changed.".
format(metadata.get('label') or metadata.get('name')),
log_message=True
)
# if metadata field contains editable_for_deployed = True, attribute
# and all its childs may be changed too. No need to check it.
if metadata.get('editable_for_deployed'):
return
# no 'fields' in metadata means that attribute has no any childs(leaf)
if 'fields' not in metadata:
if attributes != new_attributes:
raise errors.InvalidData(
"Value of '{0}' attribute couldn't be changed.".
format(metadata.get('label') or metadata.get('name')),
log_message=True
)
return
fields_sort_functions = {
'availability_zones': lambda x: x['az_name'],
'nova_computes': lambda x: x['vsphere_cluster']
}
field_name = metadata['name']
if isinstance(attributes, (list, tuple)):
if len(attributes) != len(new_attributes):
raise errors.InvalidData(
"Value of '{0}' attribute couldn't be changed.".
format(metadata.get('label') or metadata.get('name')),
log_message=True
)
attributes = sorted(
attributes, key=fields_sort_functions.get(field_name))
new_attributes = sorted(
new_attributes, key=fields_sort_functions.get(field_name))
for item, new_item in six.moves.zip(attributes, new_attributes):
for field_metadata in metadata['fields']:
cls._check_attribute(field_metadata,
item.get(field_metadata['name']),
new_item.get(field_metadata['name']))
elif isinstance(attributes, dict):
for field_metadata in metadata['fields']:
cls._check_attribute(field_metadata,
attributes.get(field_name),
new_attributes.get(field_name))
@classmethod
def _validate_nova_computes(cls, attributes, instance):
"""Validates a 'nova_computes' attributes from vmware_attributes
Raise InvalidData exception if new attributes is not valid.
:param instance: nailgun.db.sqlalchemy.models.VmwareAttributes instance
:param attributes: new attributes for db instance for validation
"""
input_nova_computes = objects.VmwareAttributes.get_nova_computes_attrs(
attributes.get('editable'))
cls.check_nova_compute_duplicate_and_empty_values(input_nova_computes)
db_nova_computes = objects.VmwareAttributes.get_nova_computes_attrs(
instance.editable)
if instance.cluster.is_locked:
cls.check_operational_controllers_settings(input_nova_computes,
db_nova_computes)
operational_compute_nodes = objects.Cluster.\
get_operational_vmware_compute_nodes(instance.cluster)
cls.check_operational_node_settings(
input_nova_computes, db_nova_computes, operational_compute_nodes)
@classmethod
def check_nova_compute_duplicate_and_empty_values(cls, attributes):
"""Check 'nova_computes' attributes for empty and duplicate values."""
nova_compute_attributes_sets = {
'vsphere_cluster': set(),
'service_name': set(),
'target_node': set()
}
for nova_compute_data in attributes:
for attr, values in six.iteritems(nova_compute_attributes_sets):
if attr == 'target_node':
settings_value = cls._get_target_node_id(nova_compute_data)
if settings_value == 'controllers':
continue
else:
settings_value = nova_compute_data.get(attr)
if not settings_value:
raise errors.InvalidData(
"Empty value for attribute '{0}' is not allowed".
format(attr),
log_message=True
)
if settings_value in values:
raise errors.InvalidData(
"Duplicate value '{0}' for attribute '{1}' is "
"not allowed".format(settings_value, attr),
log_message=True
)
values.add(settings_value)
@classmethod
def check_operational_node_settings(cls, input_nova_computes,
db_nova_computes, operational_nodes):
"""Validates a 'nova_computes' attributes for operational compute nodes
Raise InvalidData exception if nova_compute settings will be changed or
deleted for deployed nodes with role 'compute-vmware' that wasn't
marked for deletion
:param input_nova_computes: new nova_compute attributes
:type input_nova_computes: list of dicts
:param db_nova_computes: nova_computes attributes stored in db
:type db_nova_computes: list of dicts
:param operational_nodes: list of operational vmware-compute nodes
:type operational_nodes: list of nailgun.db.sqlalchemy.models.Node
"""
input_computes_by_node_name = dict(
(cls._get_target_node_id(nc), nc) for nc in input_nova_computes)
db_computes_by_node_name = dict(
(cls._get_target_node_id(nc), nc) for nc in db_nova_computes)
for node in operational_nodes:
node_hostname = node.hostname
input_nova_compute = input_computes_by_node_name.get(node_hostname)
if not input_nova_compute:
raise errors.InvalidData(
"The following compute-vmware node couldn't be "
"deleted from vSphere cluster: {0}".format(node.name),
log_message=True
)
db_nova_compute = db_computes_by_node_name.get(node_hostname)
for attr, db_value in six.iteritems(db_nova_compute):
if attr != 'target_node' and \
db_value != input_nova_compute.get(attr):
raise errors.InvalidData(
"Parameter '{0}' of nova compute instance with target "
"node '{1}' couldn't be changed".format(
attr, node.name),
log_message=True
)
@classmethod
def check_operational_controllers_settings(cls, input_nova_computes,
db_nova_computes):
"""Check deployed nova computes settings with target = controllers.
Raise InvalidData exception if any deployed nova computes clusters with
target 'controllers' were added, removed or modified.
:param input_nova_computes: new nova_compute settings
:type input_nova_computes: list of dicts
:param db_nova_computes: nova_computes settings stored in db
:type db_nova_computes: list of dicts
"""
input_computes_by_vsphere_name = dict(
(nc['vsphere_cluster'], nc) for nc in input_nova_computes if
cls._get_target_node_id(nc) == 'controllers'
)
db_clusters_names = set()
for db_nova_compute in db_nova_computes:
target_name = cls._get_target_node_id(db_nova_compute)
if target_name == 'controllers':
vsphere_name = db_nova_compute['vsphere_cluster']
input_nova_compute = \
input_computes_by_vsphere_name.get(vsphere_name)
if not input_nova_compute:
raise errors.InvalidData(
"Nova compute instance with target 'controllers' and "
"vSphere cluster {0} couldn't be deleted from "
"operational environment.".format(vsphere_name),
log_message=True
)
for attr, db_value in six.iteritems(db_nova_compute):
input_value = input_nova_compute.get(attr)
if attr == 'target_node':
db_value = cls._get_target_node_id(db_nova_compute)
input_value = cls._get_target_node_id(
input_nova_compute)
if db_value != input_value:
raise errors.InvalidData(
"Parameter '{0}' of nova compute instance with "
"vSphere cluster name '{1}' couldn't be changed".
format(attr, vsphere_name),
log_message=True
)
db_clusters_names.add(vsphere_name)
input_clusters_names = set(input_computes_by_vsphere_name)
if input_clusters_names - db_clusters_names:
raise errors.InvalidData(
"Nova compute instances with target 'controllers' couldn't be "
"added to operational environment. Check nova compute "
"instances with the following vSphere cluster names: {0}".
format(', '.join(
sorted(input_clusters_names - db_clusters_names))),
log_message=True
)
@classmethod
def validate(cls, data, instance):
d = cls.validate_json(data)
if 'metadata' in d.get('editable'):
db_metadata = instance.editable.get('metadata')
input_metadata = d.get('editable').get('metadata')
if db_metadata != input_metadata:
raise errors.InvalidData(
'Metadata shouldn\'t change',
log_message=True
)
if instance.cluster.is_locked:
cls._validate_updated_attributes(d, instance)
cls._validate_nova_computes(d, instance)
# TODO(apopovych): write validation processing from
# openstack.yaml for vmware
return d

View File

@ -64,14 +64,3 @@ collection_schema = {
"type": "object",
"items": single_schema["properties"]
}
vmware_attributes_schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Vmware attributes",
"description": "Serialized VmwareAttributes object",
"type": "object",
"required": ["editable"],
"properties": {
"editable": {"type": "object"}
}
}

View File

@ -313,8 +313,7 @@ CLUSTER_CHANGES = Enum(
'networks',
'attributes',
'disks',
'interfaces',
'vmware_attributes'
'interfaces'
)
PROVISION_METHODS = Enum(

View File

@ -20,24 +20,41 @@ Create Date: 2016-04-08 15:20:43.989472
"""
from alembic import op
from nailgun.db.sqlalchemy.models import fields
from nailgun.utils.migration import upgrade_enum
from oslo_serialization import jsonutils
import sqlalchemy as sa
from nailgun.db.sqlalchemy.models import fields
# revision identifiers, used by Alembic.
revision = 'c6edea552f1e'
down_revision = '3763c404ca48'
cluster_changes_old = (
'networks',
'attributes',
'disks',
'interfaces',
'vmware_attributes'
)
cluster_changes_new = (
'networks',
'attributes',
'disks',
'interfaces',
)
def upgrade():
upgrade_plugin_links_constraints()
upgrade_release_required_component_types()
upgrade_remove_vmware()
def downgrade():
downgrade_remove_vmware()
downgrade_release_required_component_types()
downgrade_plugin_links_constraints()
@ -107,3 +124,60 @@ def upgrade_release_required_component_types():
def downgrade_release_required_component_types():
op.drop_column('releases', 'required_component_types')
def upgrade_remove_vmware():
connection = op.get_bind()
op.drop_constraint(
'vmware_attributes_cluster_id_fkey',
'vmware_attributes',
type_='foreignkey'
)
op.drop_table('vmware_attributes')
op.drop_column('releases', 'vmware_attributes_metadata')
delete = sa.sql.text(
"""DELETE FROM cluster_changes
WHERE name = 'vmware_attributes'""")
connection.execute(delete)
upgrade_enum(
"cluster_changes", # table
"name", # column
"possible_changes", # ENUM name
cluster_changes_old, # old options
cluster_changes_new # new options
)
def downgrade_remove_vmware():
op.add_column(
'releases',
sa.Column('vmware_attributes_metadata', fields.JSON(), nullable=True))
op.create_table(
'vmware_attributes',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('cluster_id', sa.Integer()),
sa.Column('editable', fields.JSON()),
sa.ForeignKeyConstraint(['cluster_id'], ['clusters.id'], ),
sa.PrimaryKeyConstraint('id'))
upgrade_enum(
"cluster_changes", # table
"name", # column
"possible_changes", # ENUM name
cluster_changes_new, # new options
cluster_changes_old # old options
)
op.drop_constraint(
'vmware_attributes_cluster_id_fkey',
'vmware_attributes',
type_='foreignkey'
)
op.create_foreign_key(
'vmware_attributes_cluster_id_fkey',
'vmware_attributes', 'clusters',
['cluster_id'], ['id'],
ondelete='CASCADE'
)

View File

@ -33,7 +33,6 @@ from nailgun.db.sqlalchemy.models.deployment_graph import \
from nailgun.db.sqlalchemy.models.cluster import Attributes
from nailgun.db.sqlalchemy.models.cluster import Cluster
from nailgun.db.sqlalchemy.models.cluster import ClusterChanges
from nailgun.db.sqlalchemy.models.cluster import VmwareAttributes
from nailgun.db.sqlalchemy.models.release import Release

View File

@ -93,8 +93,6 @@ class Cluster(Base):
backref="cluster", cascade="delete")
changes_list = relationship("ClusterChanges", backref="cluster",
cascade="delete")
vmware_attributes = relationship("VmwareAttributes", uselist=False,
backref="cluster", cascade="delete")
# We must keep all notifications even if cluster is removed.
# It is because we want user to be able to see
# the notification history so that is why we don't use
@ -175,10 +173,3 @@ class Attributes(Base):
cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete='CASCADE'))
editable = Column(MutableDict.as_mutable(JSON))
generated = Column(MutableDict.as_mutable(JSON))
class VmwareAttributes(Base):
__tablename__ = 'vmware_attributes'
id = Column(Integer, primary_key=True)
cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete='CASCADE'))
editable = Column(MutableDict.as_mutable(JSON))

View File

@ -59,8 +59,6 @@ class Release(Base):
MutableDict.as_mutable(JSON), server_default='{}', nullable=False)
network_roles_metadata = Column(
MutableList.as_mutable(JSON), default=[], server_default='[]')
vmware_attributes_metadata = Column(
MutableDict.as_mutable(JSON), default={})
components_metadata = Column(
MutableList.as_mutable(JSON), default=[], server_default='[]')
required_component_types = Column(MutableList.as_mutable(JSON), default=[],

View File

@ -68,7 +68,6 @@
conflicts:
- controller
- cinder
- cinder-vmware
- ceph-osd
restrictions:
- condition: "settings:storage.volumes_block_device.value == false"
@ -77,19 +76,6 @@
message: "Ceph RBD cannot be used with Cinder Block Device"
tags:
- cinder-block-device
cinder-vmware:
name: "Cinder Proxy to VMware Datastore"
description: "Cinder-VMware provides scheduling of block storage resources delivered over VMware vCenter. Block storage can be used for database storage, expandable file systems, or providing a server with access to raw block level devices."
weight: 40
group: "storage"
limits:
recommended: 1
restrictions:
- condition: "settings:common.use_vcenter.value == false"
action: "hide"
message: "VMware vCenter not enabled for cluster"
tags:
- cinder-vmware
ceph-osd:
name: "Ceph OSD"
description: "Ceph storage can be configured to provide storage for block volumes (Cinder), images (Glance) and ephemeral instance storage (Nova). It can also provide object storage through the S3 and Swift API (See settings to enable each)."
@ -150,27 +136,6 @@
message: "Advanced feature should be enabled in feature groups"
tags:
- virt
compute-vmware:
name: "Compute VMware"
description: "A node that runs nova-compute with VCDriver, that manages ESXi computing resources via VMware vCenter."
weight: 90
group: "compute"
conflicts:
- controller
- compute
- cinder
- cinder-block-device
- ceph-osd
- mongo
- base-os
- virt
- ironic
restrictions:
- condition: "settings:common.use_vcenter.value == false"
action: "hide"
message: "VMware vCenter not enabled for cluster"
tags:
- compute-vmware
ironic:
name: "Ironic"
description: "Ironic conductor."
@ -203,8 +168,6 @@
has_primary: false
cinder-block-device:
has_primary: false
cinder-vmware:
has_primary: false
ceph-osd:
has_primary: false
mongo:
@ -213,8 +176,6 @@
has_primary: false
virt:
has_primary: false
compute-vmware:
has_primary: false
ironic:
has_primary: false
@ -629,8 +590,6 @@
cinder:
- {allocate_size: "min", id: "os"}
- {allocate_size: "all", id: "cinder"}
cinder-vmware:
- {allocate_size: "min", id: "os"}
ceph-osd:
- {allocate_size: "min", id: "os"}
- {allocate_size: "min", id: "cephjournal"}
@ -652,8 +611,6 @@
virt:
- {allocate_size: "min", id: "os"}
- {allocate_size: "all", id: "vm"}
compute-vmware:
- {allocate_size: "min", id: "os"}
ironic:
- {allocate_size: "min", id: "os"}
- {allocate_size: "min", id: "logs"}
@ -1088,10 +1045,6 @@
description: "Uncheck this box if the public gateway will not be available or will not respond to ICMP requests to the deployed cluster. If unchecked, the controllers will not take public gateway availability into account as part of the cluster health. If the cluster will not have internet access, you will need to make sure to provide proper offline mirrors for the deployment to succeed."
weight: 50
type: "checkbox"
use_vcenter:
value: false
weight: 30
type: "hidden"
libvirt_type:
value: "qemu"
values:
@ -1502,19 +1455,6 @@
description: "Configures Glance to use the Ceph RBD backend to store images. If enabled, this option will prevent Swift from installing."
weight: 30
type: "checkbox"
restrictions:
- "settings:storage.images_vcenter.value == true": "Only one Glance backend could be selected."
images_vcenter:
value: false
label: "VMware vCenter/ESXi datastore for images (Glance)"
description: "Configures Glance to use the vCenter/ESXi backend to store images. If enabled, this option will prevent Swift from installing."
weight: 35
type: "checkbox"
restrictions:
- condition: "settings:common.use_vcenter.value != true"
action: "hide"
- condition: "settings:storage.images_ceph.value == true"
message: "Only one Glance backend could be selected."
ephemeral_ceph:
value: false
label: "Ceph RBD for ephemeral volumes (Nova)"
@ -1681,182 +1621,6 @@
modules: "rsync://{settings.MASTER_IP}:/puppet/{cluster.release.version}/modules/"
deployed_before:
value: false
vmware_attributes_metadata:
editable:
metadata:
-
name: "availability_zones"
type: "array"
restrictions:
- condition: "settings:common.use_vcenter.value == false"
message: "VMware vCenter not enabled for cluster"
fields:
-
name: "az_name"
type: "text"
label: "Availability zone"
description: "Availability zone name"
regex:
source: &availability_zone_blacklist '^(?!nova$)\w+$'
error: "Invalid availability zone name"
-
name: "vcenter_host"
type: "text"
label: "vCenter host"
description: "vCenter host or IP"
regex:
source: *ipv4_or_hostname_regex
error: "Invalid vCenter host"
-
name: "vcenter_username"
type: "text"
label: "vCenter username"
description: "vCenter username"
regex:
source: *non_empty_string
error: "Empty vCenter username"
-
name: "vcenter_password"
type: "password"
label: "vCenter password"
description: "vCenter password"
regex:
source: *non_empty_string
error: "Empty vCenter password"
-
name: "vcenter_security_disabled"
type: "checkbox"
label: "Bypass vCenter certificate verification"
-
name: "vcenter_ca_file"
type: "file"
label: "CA file"
description: "File containing the trusted CA bundle that emitted vCenter server certificate. Even if CA bundle is not uploaded, certificate verification is turned on."
restrictions:
- condition: "current_vcenter:vcenter_security_disabled == true"
message: "Bypass vCenter certificate verification should be disabled."
-
name: "nova_computes"
type: "array"
editable_for_deployed: true
fields:
-
name: "vsphere_cluster"
type: "text"
label: "vSphere cluster"
description: "vSphere cluster"
regex:
source: *non_empty_string
error: "Invalid vSphere cluster"
-
name: "service_name"
type: "text"
label: "Service name"
description: "Service name"
regex:
source: '^\w[\w\-]+$'
error: "Invalid service name"
-
name: "datastore_regex"
type: "text"
label: "Datastore regex"
description: "Datastore regex"
regex:
source: *non_empty_string
error: "Invalid datastore regex"
-
name: "target_node"
type: "select"
label: "Target node"
description: "Target node for nova-compute service"
-
name: "glance"
type: "object"
restrictions:
- condition: "settings:storage.images_vcenter.value == false or settings:common.use_vcenter.value == false"
message: "VMware vCenter datastore for images is not enabled in Settings tab"
fields:
-
name: "vcenter_host"
type: "text"
label: "vCenter host"
description: "vCenter host or IP"
regex:
source: *ipv4_or_hostname_regex
error: "Invalid vCenter host"
-
name: "vcenter_username"
type: "text"
label: "vCenter username"
description: "vCenter username"
regex:
source: *non_empty_string
error: "Empty vCenter username"
-
name: "vcenter_password"
type: "password"
label: "vCenter password"
description: "vCenter password"
regex:
source: *non_empty_string
error: "Empty vCenter password"
-
name: "datacenter"
type: "text"
label: "Datacenter"
description: "Datacenter"
regex:
source: *non_empty_string
error: "Invalid datacenter"
-
name: "datastore"
type: "text"
label: "Datastore"
description: "Datastore"
regex:
source: *non_empty_string
error: "Invalid datastore"
-
name: "vcenter_security_disabled"
type: "checkbox"
label: "Bypass vCenter certificate verification"
-
name: "ca_file"
type: "file"
label: "CA file"
description: "File containing the trusted CA bundle that emitted vCenter server certificate. Even if CA bundle is not uploaded, certificate verification is turned on."
restrictions:
- condition: "glance:vcenter_security_disabled == true"
message: "Bypass vCenter certificate verification should be disabled."
value:
availability_zones:
-
az_name: "vcenter"
vcenter_host: ""
vcenter_username: ""
vcenter_password: ""
vcenter_security_disabled: true
vcenter_ca_file: {}
nova_computes:
-
vsphere_cluster: ""
service_name: ""
datastore_regex: ""
target_node:
options:
- id: "controllers"
label: "controllers"
current:
id: "controllers"
label: "controllers"
glance:
vcenter_host: ""
vcenter_username: ""
vcenter_password: ""
datacenter: ""
datastore: ""
vcenter_security_disabled: true
ca_file: {}
components_metadata:
- name: hypervisor:qemu
default: true
@ -1866,26 +1630,7 @@
label: "dialog.create_cluster_wizard.compute.qemu"
description: "dialog.create_cluster_wizard.compute.qemu_description"
compatible:
- name: hypervisor:vmware
- name: hypervisor:vmware
weight: 15
bind:
- "settings:common.use_vcenter.value"
label: "dialog.create_cluster_wizard.compute.vcenter"
description: "dialog.create_cluster_wizard.compute.vcenter_description"
compatible:
- name: hypervisor:qemu
requires:
- one_of:
items:
- hypervisor:qemu
message: "dialog.create_cluster_wizard.compute.vcenter_warning"
- one_of:
items:
- network:neutron:ml2:dvs
- network:neutron:ml2:nsx
message: "dialog.create_cluster_wizard.compute.vcenter_requires_network_backend"
message_invalid: "dialog.create_cluster_wizard.compute.vcenter_requires_network_plugins"
- name: hypervisor:*
- name: network:neutron:core:ml2
default: true
weight: 1000
@ -1908,7 +1653,6 @@
compatible:
- name: network:neutron:core:ml2
- name: hypervisor:qemu
- name: hypervisor:vmware
requires:
- one_of:
items:
@ -1926,8 +1670,6 @@
incompatible:
- name: network:neutron:ml2:vlan
message: "dialog.create_cluster_wizard.network.vlan_tun_alert"
- name: hypervisor:vmware
message: "dialog.create_cluster_wizard.network.hypervisor_alert"
- name: additional_service:ironic
message: "dialog.create_cluster_wizard.additional.ironic_network_mode_alert"
requires:
@ -1943,7 +1685,6 @@
- "settings:storage.volumes_lvm.value"
compatible:
- name: hypervisor:qemu
- name: hypervisor:vmware
- name: network:neutron:core:ml2
- name: network:neutron:ml2:vlan
- name: network:neutron:ml2:tun
@ -1959,7 +1700,6 @@
- "settings:storage.volumes_lvm.value": false
compatible:
- name: hypervisor:qemu
- name: hypervisor:vmware
- name: network:neutron:core:ml2
- name: network:neutron:ml2:vlan
- name: network:neutron:ml2:tun
@ -1977,7 +1717,6 @@
- "settings:storage.objects_ceph.value"
compatible:
- name: hypervisor:qemu
- name: hypervisor:vmware
- name: network:neutron:core:ml2
- name: network:neutron:ml2:vlan
- name: network:neutron:ml2:tun
@ -1993,7 +1732,6 @@
- "settings:storage.ephemeral_ceph.value"
compatible:
- name: hypervisor:qemu
- name: hypervisor:vmware
- name: network:neutron:core:ml2
- name: network:neutron:ml2:vlan
- name: network:neutron:ml2:tun
@ -2009,7 +1747,6 @@
- "settings:storage.images_ceph.value"
compatible:
- name: hypervisor:qemu
- name: hypervisor:vmware
- name: network:neutron:core:ml2
- name: network:neutron:ml2:vlan
- name: network:neutron:ml2:tun
@ -2025,7 +1762,6 @@
description: "dialog.create_cluster_wizard.additional.install_sahara_description"
compatible:
- name: hypervisor:qemu
- name: hypervisor:vmware
- name: network:neutron:core:ml2
- name: network:neutron:ml2:vlan
- name: network:neutron:ml2:tun
@ -2046,7 +1782,6 @@
description: "dialog.create_cluster_wizard.additional.install_murano_description"
compatible:
- name: hypervisor:qemu
- name: hypervisor:vmware
- name: network:neutron:core:ml2
- name: network:neutron:ml2:vlan
- name: network:neutron:ml2:tun
@ -2066,7 +1801,6 @@
description: "dialog.create_cluster_wizard.additional.install_ceilometer_description"
compatible:
- name: hypervisor:qemu
- name: hypervisor:vmware
- name: network:neutron:core:ml2
- name: network:neutron:ml2:vlan
- name: network:neutron:ml2:tun

View File

@ -159,12 +159,6 @@
"package_version": "2.0.0",
"attributes_metadata": {
"metadata": {
"restrictions": [
{
"condition": "settings:common.use_vcenter.value == true",
"action": "hide"
}
]
},
"zabbix_text_1": {
"value": "value 1.1",

View File

@ -1,245 +0,0 @@
[{
"pk": 1,
"editable": {
"metadata": [
{
"fields": [
{
"type": "text",
"description": "Availability zone name",
"name": "az_name",
"label": "AZ name"
},
{
"type": "text",
"description": "vCenter host or IP",
"name": "vcenter_host",
"label": "vCenter host"
},
{
"type": "text",
"description": "vCenter username",
"name": "vcenter_username",
"label": "vCenter username"
},
{
"type": "password",
"description": "vCenter password",
"name": "vcenter_password",
"label": "vCenter password"
},
{
"type": "checkbox",
"name": "vcenter_security_disabled",
"label": "Bypass vCenter certificate verification"
},
{
"type": "file",
"description": "File containing the trusted CA bundle that emitted vCenter server certificate. Even if CA bundle is not uploaded, certificate verification is turned on.",
"name": "vcenter_ca_file",
"label": "CA file",
"restrictions": [
{
"condition": "current_vcenter:vcenter_security_disabled == true",
"message": "Bypass vCenter certificate verification should be disabled."
}
]
},
{
"fields": [
{
"type": "text",
"description": "vSphere Cluster",
"name": "vsphere_cluster",
"label": "vSphere Cluster",
"regex": {
"source": "\\S",
"error": "Empty cluster"
}
},
{
"type": "text",
"description": "Service name",
"name": "service_name",
"label": "Service name"
},
{
"type": "text",
"description": "Datastore regex",
"name": "datastore_regex",
"label": "Datastore regex"
},
{
"type": "select",
"description": "Target node for nova-compute service",
"name": "target_node",
"label": "Target node"
}
],
"type": "array",
"name": "nova_computes"
}
],
"type": "array",
"name": "availability_zones"
},
{
"fields": [
{
"type": "text",
"description": "VLAN interface",
"name": "esxi_vlan_interface",
"label": "VLAN interface"
}
],
"type": "object",
"name": "network"
},
{
"fields": [
{
"type": "text",
"description": "VCenter host or IP",
"name": "vcenter_host",
"label": "VCenter Host",
"regex": {
"source": "\\S",
"error": "Empty host"
}
},
{
"type": "text",
"description": "vCenter username",
"name": "vcenter_username",
"label": "vCenter username",
"regex": {
"source": "\\S",
"error": "Empty username"
}
},
{
"type": "password",
"description": "vCenter password",
"name": "vcenter_password",
"label": "vCenter password",
"regex": {
"source": "\\S",
"error": "Empty password"
}
},
{
"type": "text",
"description": "Datacenter",
"name": "datacenter",
"label": "Datacenter",
"regex": {
"source": "\\S",
"error": "Empty datacenter"
}
},
{
"type": "text",
"description": "Datastore",
"name": "datastore",
"label": "Datastore",
"regex": {
"source": "\\S",
"error": "Empty datastore"
}
},
{
"type": "checkbox",
"name": "vcenter_security_disabled",
"label": "Bypass vCenter certificate verification"
},
{
"type": "file",
"description": "File containing the trusted CA bundle that emitted vCenter server certificate. Even if CA bundle is not uploaded, certificate verification is turned on.",
"name": "ca_file",
"label": "CA file",
"restrictions": [
{
"condition": "glance:vcenter_security_disabled == true",
"message": "Bypass vCenter certificate verification should be disabled."
}
]
}
],
"type": "object",
"name": "glance",
"restrictions": [
{
"action": "hide",
"condition": "settings:storage.images_vcenter.value == false or settings:common.use_vcenter.value == false"
}
]
}
],
"value": {
"availability_zones": [
{
"az_name": "Zone 1",
"vcenter_host": "1.2.3.4",
"vcenter_username": "admin",
"vcenter_password": "secret",
"vcenter_security_disabled": "true",
"vcenter_ca_file": "file_blob",
"nova_computes": [
{
"vsphere_cluster": "cluster1",
"service_name": "Compute 1",
"datastore_regex": "",
"target_node": {
"current": {
"id": "test_target_node"
}
}
},
{
"vsphere_cluster": "cluster2",
"service_name": "Compute 3",
"datastore_regex": "",
"target_node": {
"current": {
"id": "test_target_node"
}
}
}
]
},
{
"az_name": "Zone 2",
"vcenter_host": "1.2.3.6",
"vcenter_username": "user$",
"vcenter_password": "pass$word",
"vcenter_security_disabled": "true",
"vcenter_ca_file": "file_blob",
"nova_computes": [
{
"vsphere_cluster": "cluster1",
"service_name": "Compute 4",
"datastore_regex": "^openstack-[0-9]$"
},
{
"vsphere_cluster": "",
"service_name": "Compute 7",
"datastore_regex": ""
}
]
}
],
"glance": {
"vcenter_host": "1.2.3.4",
"vcenter_username": "admin",
"vcenter_password": "secret",
"datacenter": "test_datacenter",
"datastore": "test_datastore",
"vcenter_security_disabled": "true",
"ca_file": "file_blob"
},
"network": {
"esxi_vlan_interface": "eth0"
}
}
}
}]

View File

@ -34,7 +34,6 @@ from nailgun.objects.release import ReleaseCollection
from nailgun.objects.cluster import Attributes
from nailgun.objects.cluster import Cluster
from nailgun.objects.cluster import ClusterCollection
from nailgun.objects.cluster import VmwareAttributes
from nailgun.objects.task import Task
from nailgun.objects.task import TaskCollection

View File

@ -176,7 +176,6 @@ class Cluster(NailgunObject):
cls.create_default_group(cluster)
cls.create_attributes(cluster, enabled_editable_attributes)
cls.create_vmware_attributes(cluster)
cls.create_default_extensions(cluster)
# default graph should be created in any case
@ -184,8 +183,6 @@ class Cluster(NailgunObject):
cls.add_pending_changes(
cluster, consts.CLUSTER_CHANGES.attributes)
cls.add_pending_changes(
cluster, consts.CLUSTER_CHANGES.vmware_attributes)
ClusterPlugin.add_compatible_plugins(cluster)
PluginManager.enable_plugins_by_components(cluster)
@ -1329,20 +1326,6 @@ class Cluster(NailgunObject):
return volumes_metadata
@classmethod
def create_vmware_attributes(cls, instance):
"""Store VmwareAttributes instance into DB."""
vmware_metadata = instance.release.vmware_attributes_metadata
if vmware_metadata:
return VmwareAttributes.create(
{
"editable": vmware_metadata.get("editable"),
"cluster_id": instance.id
}
)
return None
@classmethod
def get_create_data(cls, instance):
"""Return common parameters cluster was created with.
@ -1363,52 +1346,6 @@ class Cluster(NailgunObject):
get_network_config_create_data(instance))
return data
@classmethod
def get_vmware_attributes(cls, instance):
"""Get VmwareAttributes instance from DB.
Now we have relation with cluster 1:1.
"""
return db().query(models.VmwareAttributes).filter(
models.VmwareAttributes.cluster_id == instance.id
).first()
@classmethod
def get_default_vmware_attributes(cls, instance):
"""Get metadata from release with empty value section."""
editable = instance.release.vmware_attributes_metadata.get("editable")
editable = traverse(
editable,
formatter_context={'cluster': instance, 'settings': settings},
keywords={'generator': AttributesGenerator.evaluate}
)
return editable
@classmethod
def update_vmware_attributes(cls, instance, data):
"""Update Vmware attributes.
Actually we allways update only value section in editable.
"""
metadata = instance.vmware_attributes.editable['metadata']
value = data.get('editable', {}).get('value')
vmware_attr = {
'metadata': metadata,
'value': value
}
setattr(instance.vmware_attributes, 'editable', vmware_attr)
cls.add_pending_changes(instance, "vmware_attributes")
db().flush()
vmware_attr.pop('metadata')
return vmware_attr
@classmethod
def is_vmware_enabled(cls, instance):
"""Check if current cluster supports vmware configuration."""
attributes = cls.get_editable_attributes(instance)
return attributes.get('common', {}).get('use_vcenter', {}).get('value')
@staticmethod
def adjust_nodes_lists_on_controller_removing(instance, nodes_to_delete,
nodes_to_deploy):
@ -1582,31 +1519,6 @@ class Cluster(NailgunObject):
instance, instance.nodes if nodes is None else nodes
)
@classmethod
def has_compute_vmware_changes(cls, instance):
"""Checks if any 'compute-vmware' nodes are waiting for deployment.
:param instance: cluster for checking
:type instance: nailgun.db.sqlalchemy.models.Cluster instance
"""
compute_vmware_nodes_query = db().query(models.Node).filter_by(
cluster_id=instance.id
).filter(sa.or_(
sa.and_(models.Node.roles.any('compute-vmware'),
models.Node.pending_deletion),
models.Node.pending_roles.any('compute-vmware')
))
return db().query(compute_vmware_nodes_query.exists()).scalar()
@classmethod
def get_operational_vmware_compute_nodes(cls, instance):
return db().query(models.Node).filter_by(
cluster_id=instance.id
).filter(
models.Node.roles.any('compute-vmware'),
sa.not_(models.Node.pending_deletion)
).all()
@classmethod
def is_task_deploy_enabled(cls, instance):
"""Tests that task based deploy is enabled.
@ -1708,26 +1620,3 @@ class ClusterCollection(NailgunCollection):
#: Single Cluster object class
single = Cluster
class VmwareAttributes(NailgunObject):
model = models.VmwareAttributes
@staticmethod
def get_nova_computes_attrs(attributes):
return attributes.get('value', {}).get(
'availability_zones', [{}])[0].get('nova_computes', [])
@classmethod
def get_nova_computes_target_nodes(cls, instance):
"""Get data of targets node for all nova computes.
:param instance: nailgun.db.sqlalchemy.models.Cluster instance
:returns: list of dicts that represents nova compute targets
"""
nova_compute_target_nodes = []
for nova_compute in cls.get_nova_computes_attrs(instance.editable):
target = nova_compute['target_node']['current']
if target['id'] != 'controllers':
nova_compute_target_nodes.append(target)
return nova_compute_target_nodes

View File

@ -31,7 +31,6 @@ class ReleaseSerializer(BasicSerializer):
"tags_metadata",
"state",
"attributes_metadata",
"vmware_attributes_metadata",
"components_metadata"
)

View File

@ -146,105 +146,3 @@ class MuranoMetadataSerializerMixin(object):
test_vm_image['properties']['murano_image_info'] = \
"""'{"title": "Murano Demo", "type": "cirros.demo"}'"""
return {'test_vm_image': test_vm_image}
class VmwareDeploymentSerializerMixin(object):
def generate_vmware_data(self, node):
"""Extend serialize data with vmware attributes"""
vmware_data = {}
use_vcenter = node.cluster.attributes.editable.get('common', {}) \
.get('use_vcenter', {}).get('value')
if use_vcenter:
compute_instances = []
cinder_instances = []
vmware_attributes = node.cluster.vmware_attributes.editable \
.get('value', {})
availability_zones = vmware_attributes \
.get('availability_zones', {})
glance_instance = vmware_attributes.get('glance', {})
network = vmware_attributes.get('network', {})
for zone in availability_zones:
vc_user = self.escape_dollar(zone.get('vcenter_username', ''))
vc_password = self.escape_dollar(zone.get('vcenter_password',
''))
for compute in zone.get('nova_computes', {}):
datastore_regex = \
self.escape_dollar(compute.get('datastore_regex', ''))
compute_item = {
'availability_zone_name': zone.get('az_name', ''),
'vc_host': zone.get('vcenter_host', ''),
'vc_user': vc_user,
'vc_password': vc_password,
'vc_insecure': zone.get('vcenter_security_disabled',
''),
'vc_ca_file': zone.get('vcenter_ca_file', ''),
'service_name': compute.get('service_name', ''),
'vc_cluster': compute.get('vsphere_cluster', ''),
'datastore_regex': datastore_regex,
'target_node': compute.get('target_node', {}).get(
'current', {}).get('id', 'controllers')
}
compute_instances.append(compute_item)
cinder_item = {
'availability_zone_name': zone.get('az_name', ''),
'vc_host': zone.get('vcenter_host', ''),
'vc_user': vc_user,
'vc_password': vc_password,
'vc_insecure': zone.get('vcenter_security_disabled', ''),
'vc_ca_file': zone.get('vcenter_ca_file', '')
}
cinder_instances.append(cinder_item)
vmware_data['use_vcenter'] = True
if compute_instances:
vmware_data['vcenter'] = {
'esxi_vlan_interface':
network.get('esxi_vlan_interface', ''),
'computes': compute_instances
}
if cinder_instances:
vmware_data['cinder'] = {
'instances': cinder_instances
}
if glance_instance:
glance_username = \
self.escape_dollar(glance_instance
.get('vcenter_username', ''))
glance_password = \
self.escape_dollar(glance_instance
.get('vcenter_password', ''))
vmware_data['glance'] = {
'vc_host': glance_instance.get('vcenter_host', ''),
'vc_user': glance_username,
'vc_password': glance_password,
'vc_datacenter': glance_instance.get('datacenter', ''),
'vc_datastore': glance_instance.get('datastore', ''),
'vc_insecure': glance_instance.get(
'vcenter_security_disabled', ''),
'vc_ca_file': glance_instance.get('ca_file', '')
}
return vmware_data
@staticmethod
def escape_dollar(data):
"""Escape dollar symbol
In order to disable variable interpolation in
values that we write to configuration files during
deployment we must replace all $ (dollar sign) occurrences.
"""
return data.replace('$', '$$')

View File

@ -16,7 +16,6 @@
"""Deployment serializers for orchestrator"""
from copy import deepcopy
from distutils.version import StrictVersion
import six
@ -33,8 +32,6 @@ from nailgun.utils.resolvers import NameMatchingPolicy
from nailgun.utils.resolvers import TagResolver
from nailgun.orchestrator.base_serializers import MuranoMetadataSerializerMixin
from nailgun.orchestrator.base_serializers import \
VmwareDeploymentSerializerMixin
from nailgun.orchestrator.provisioning_serializers import \
ProvisionLCMSerializer
@ -266,18 +263,6 @@ class DeploymentMultinodeSerializer(object):
properties_data = {}
# Alternate VMWare specific values.
if c_attrs['editable']['common']['libvirt_type']['value'] == 'vcenter':
image_data.update({
'disk_format': 'vmdk',
'img_path': '{0}cirros-i386-disk.vmdk'.format(img_dir),
})
properties_data = {
'vmware_disktype': 'sparse',
'vmware_adaptertype': 'lsiLogic',
'hypervisor_type': 'vmware'
}
# NOTE(aschultz): properties was added as part of N and should be
# used infavor of glance_properties
image_data['glance_properties'] = self.generate_properties_arguments(
@ -426,8 +411,7 @@ class DeploymentHASerializer60(DeploymentHASerializer50):
neutron_serializers.NeutronNetworkDeploymentSerializer60
class DeploymentMultinodeSerializer61(DeploymentMultinodeSerializer,
VmwareDeploymentSerializerMixin):
class DeploymentMultinodeSerializer61(DeploymentMultinodeSerializer):
nova_network_serializer = \
nova_serializers.NovaNetworkDeploymentSerializer61
@ -438,7 +422,6 @@ class DeploymentMultinodeSerializer61(DeploymentMultinodeSerializer,
base = super(DeploymentMultinodeSerializer61, self)
serialized_node = base.serialize_node(node, role)
serialized_node['user_node_name'] = node.name
serialized_node.update(self.generate_vmware_data(node))
return serialized_node
@ -451,8 +434,7 @@ class DeploymentMultinodeSerializer61(DeploymentMultinodeSerializer,
return serialized_node
class DeploymentHASerializer61(DeploymentHASerializer,
VmwareDeploymentSerializerMixin):
class DeploymentHASerializer61(DeploymentHASerializer):
nova_network_serializer = \
nova_serializers.NovaNetworkDeploymentSerializer61
@ -463,7 +445,6 @@ class DeploymentHASerializer61(DeploymentHASerializer,
base = super(DeploymentHASerializer61, self)
serialized_node = base.serialize_node(node, role)
serialized_node['user_node_name'] = node.name
serialized_node.update(self.generate_vmware_data(node))
return serialized_node
@ -475,49 +456,6 @@ class DeploymentHASerializer61(DeploymentHASerializer,
serialized_node['user_node_name'] = node.name
return serialized_node
# Alternate VMWare specific values.
# FiXME(who): srogov
# This a temporary workaround to keep existing functioanality
# after fully implementation of the multi HV support and astute part
# for multiple images support, it is need to change
# dict image_data['test_vm_image'] to list of dicts
def generate_test_vm_image_data(self, node):
attrs = node.cluster.attributes
image_data = super(
DeploymentHASerializer61,
self).generate_test_vm_image_data(node)
images_data = {}
images_data['test_vm_image'] = []
if attrs.get('editable', {}).get('common', {}). \
get('use_vcenter', {}).get('value') is True:
image_vmdk_data = deepcopy(image_data['test_vm_image'])
img_path = image_vmdk_data['img_path']. \
replace('x86_64-disk.img', 'i386-disk.vmdk')
image_vmdk_data.update({
'img_name': 'TestVM-VMDK',
'disk_format': 'vmdk',
'img_path': img_path,
})
properties_data = {
'vmware_disktype': 'sparse',
'vmware_adaptertype': 'lsiLogic',
'hypervisor_type': 'vmware'
}
glance_properties = self.generate_properties_arguments(
properties_data)
# NOTE(aschultz): properties was added as part of N and should be
# used infavor of glance_properties
image_vmdk_data['glance_properties'] = glance_properties
image_vmdk_data['properties'] = properties_data
images_data['test_vm_image'].append(image_vmdk_data)
images_data['test_vm_image'].append(image_data['test_vm_image'])
else:
images_data = image_data
return images_data
class DeploymentHASerializer70(DeploymentHASerializer61):
# nova_network_serializer is just for compatibility with current BVTs

View File

@ -436,8 +436,6 @@ class PluginAdapterV5(PluginAdapterV4):
"components": "components_metadata",
"vmware_attributes": "vmware_attributes_metadata",
"os": "operating_system"
}

View File

@ -105,8 +105,6 @@ class InstallationInfo(object):
'volumes_ceph', None),
WhiteListRule(('storage', 'images_ceph', 'value'),
'images_ceph', None),
WhiteListRule(('storage', 'images_vcenter', 'value'),
'images_vcenter', None),
WhiteListRule(('storage', 'ephemeral_ceph', 'value'),
'ephemeral_ceph', None),
WhiteListRule(('storage', 'objects_ceph', 'value'),
@ -168,17 +166,6 @@ class InstallationInfo(object):
'brute_force_protection', bool),
)
vmware_attributes_white_list = (
# ((path, to, property), 'map_to_name', transform_function)
WhiteListRule(('value', 'availability_zones', 'cinder', 'enable'),
'vmware_az_cinder_enable', None),
# We add 'vsphere_cluster' into path for enter into nested list.
# Private value of 'vsphere_cluster' is not collected, we only
# computes length of the nested list
WhiteListRule(('value', 'availability_zones', 'nova_computes',
'vsphere_cluster'), 'vmware_az_nova_computes_num', len),
)
plugin_info_white_list = (
# ((path, to, property), 'map_to_name', transform_function)
WhiteListRule(('id',), 'id', None),
@ -278,9 +265,6 @@ class InstallationInfo(object):
release = cluster.release
nodes_num = NodeCollection.filter_by(
None, cluster_id=cluster.id).count()
vmware_attributes_editable = None
if cluster.vmware_attributes:
vmware_attributes_editable = cluster.vmware_attributes.editable
cluster_info = {
'id': cluster.id,
'nodes_num': nodes_num,
@ -298,10 +282,6 @@ class InstallationInfo(object):
Cluster.get_editable_attributes(cluster),
self.attributes_white_list
),
'vmware_attributes': self.get_attributes(
vmware_attributes_editable,
self.vmware_attributes_white_list
),
'plugin_links': self.get_plugin_links(
cluster.plugin_links),
'net_provider': cluster.net_provider,

View File

@ -57,7 +57,6 @@ from nailgun.task.helpers import TaskHelper
from nailgun.task.legacy_tasks_adapter import adapt_legacy_tasks
from nailgun.utils import logs as logs_utils
from nailgun.utils.resolvers import TagResolver
from nailgun.utils.restrictions import VmwareAttributesRestriction
def make_astute_message(task, method, respond_to, args):
@ -1521,7 +1520,6 @@ class CheckBeforeDeploymentTask(object):
cls._check_nodes_roles(task)
cls._check_ceph(task)
cls._check_public_network(task)
cls._check_vmware_consistency(task)
cls._validate_network_template(task)
# TODO(asvechnikov): Make an appropriate versioning of tasks
@ -1660,101 +1658,6 @@ class CheckBeforeDeploymentTask(object):
raise errors.MongoNodesCheckError
@classmethod
def _check_vmware_consistency(cls, task):
"""Checks vmware attributes consistency and proper values."""
attributes = objects.Cluster.get_editable_attributes(task.cluster)
vmware_attributes = task.cluster.vmware_attributes
# Old(< 6.1) clusters haven't vmware support
if vmware_attributes:
cinder_nodes = [node for node in task.cluster.nodes if
'cinder' in node.all_roles]
if not cinder_nodes:
logger.info('There is no any node with "cinder" role provided')
compute_vmware_nodes = [node for node in task.cluster.nodes if
'compute-vmware' in node.all_roles]
if compute_vmware_nodes:
cls._check_vmware_nova_computes(compute_vmware_nodes,
vmware_attributes)
models = {
'settings': attributes,
'default': vmware_attributes.editable,
'cluster': task.cluster,
'current_vcenter': vmware_attributes.editable['value'].get(
'availability_zones')[0],
'glance': vmware_attributes.editable['value'].get('glance'),
'version': settings.VERSION,
'networking_parameters': task.cluster.network_config
}
errors_msg = VmwareAttributesRestriction.check_data(
models=models,
metadata=vmware_attributes.editable['metadata'],
data=vmware_attributes.editable['value'])
if errors_msg:
raise errors.CheckBeforeDeploymentError('\n'.join(errors_msg))
@classmethod
def _check_vmware_nova_computes(cls, compute_vmware_nodes, attributes):
"""Check that nova computes settings is correct for cluster nodes
:param compute_vmware_nodes: all node with role compute-vmware that
belongs to cluster
:type compute_vmware_nodes: list of nailgun.db.sqlalchemy.models.Node
instances
:param attributes: cluster vmware_attributes
:type attributes: nailgun.db.sqlalchemy.models.VmwareAttributes
:raises: errors.CheckBeforeDeploymentError
"""
compute_nodes_targets = \
objects.VmwareAttributes.get_nova_computes_target_nodes(attributes)
compute_nodes_hostnames = set([t['id'] for t in compute_nodes_targets])
errors_msg = []
cluster_nodes_hostname = set()
not_deleted_nodes_from_computes = set()
not_assigned_nodes_to_computes = set()
for node in compute_vmware_nodes:
node_hostname = node.hostname
if node.pending_deletion:
if node_hostname in compute_nodes_hostnames:
not_deleted_nodes_from_computes.add(node.name)
elif node_hostname not in compute_nodes_hostnames:
not_assigned_nodes_to_computes.add(node.name)
cluster_nodes_hostname.add(node_hostname)
if not_assigned_nodes_to_computes:
errors_msg.append(
"The following compute-vmware nodes are not assigned to "
"any vCenter cluster: {0}".format(
', '.join(sorted(not_assigned_nodes_to_computes))
)
)
if not_deleted_nodes_from_computes:
errors_msg.append(
"The following nodes are prepared for deletion and "
"couldn't be assigned to any vCenter cluster: {0}".format(
', '.join(sorted(not_deleted_nodes_from_computes))
),
)
alien_nodes_names = [t['label'] for t in compute_nodes_targets if
t['id'] not in cluster_nodes_hostname]
if alien_nodes_names:
errors_msg.append(
"The following nodes don't belong to compute-vmware nodes of "
"environment and couldn't be assigned to any vSphere cluster: "
"{0}".format(', '.join(sorted(alien_nodes_names)))
)
if errors_msg:
raise errors.CheckBeforeDeploymentError('\n'.join(errors_msg))
@classmethod
def _validate_network_template(cls, task):
cluster = task.cluster

View File

@ -331,7 +331,6 @@ class EnvironmentManager(object):
'name': 'cluster-api-' + str(randint(0, 1000000)),
}
editable_attributes = kwargs.pop('editable_attributes', None)
vmware_attributes = kwargs.pop('vmware_attributes', None)
if kwargs:
cluster_data.update(kwargs)
@ -364,8 +363,7 @@ class EnvironmentManager(object):
if editable_attributes:
Cluster.patch_attributes(cluster_db,
{'editable': editable_attributes})
if vmware_attributes:
Cluster.update_vmware_attributes(cluster_db, vmware_attributes)
return cluster_db
def create_node(
@ -1074,10 +1072,6 @@ class EnvironmentManager(object):
default_components[0].update(kwargs)
return default_components
def get_default_vmware_attributes_metadata(self):
return self.read_fixtures(
['openstack'])[0]['fields']['vmware_attributes_metadata']
def upload_fixtures(self, fxtr_names):
for fxtr_path in self.fxtr_paths_by_names(fxtr_names):
with open(fxtr_path, "r") as fxtr_file:

View File

@ -14,7 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
from mock import patch
from oslo_serialization import jsonutils
import six
@ -604,231 +603,6 @@ class TestAlwaysEditable(BaseIntegrationTest):
}])
class TestVmwareAttributes(BaseIntegrationTest):
def setUp(self):
super(TestVmwareAttributes, self).setUp()
self.cluster = self.env.create_cluster(api=True)
def test_vmware_attributes_creation(self):
self._set_use_vcenter(self.cluster)
resp = self.app.get(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': self.cluster['id']}),
headers=self.default_headers
)
release = objects.Release.get_by_uid(self.cluster['release_id'])
self.assertEqual(200, resp.status_code)
attrs = objects.Cluster.get_vmware_attributes(self.cluster)
# TODO(apopovych): use dictdiffer 0.3.0 to compare atttributes
# one-by-one
self.assertEqual(
release.vmware_attributes_metadata['editable'],
attrs.editable
)
def test_vmware_attributes_update(self):
self._set_use_vcenter(self.cluster)
resp = self.app.put(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': self.cluster['id']}),
params=jsonutils.dumps({
"editable": {
"value": {"foo": "bar"}
}
}),
headers=self.default_headers
)
self.assertEqual(200, resp.status_code)
attrs = objects.Cluster.get_vmware_attributes(self.cluster)
self.assertEqual('bar', attrs.editable.get('value', {}).get('foo'))
attrs.editable.get('value', {}).pop('foo')
self.assertEqual(attrs.editable.get('value'), {})
def test_vmware_attributes_update_with_invalid_json_format(self):
self._set_use_vcenter(self.cluster)
resp = self.app.put(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': self.cluster['id']}),
params=jsonutils.dumps({
"value": {"foo": "bar"}
}),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(400, resp.status_code)
self.assertEqual(
"'editable' is a required property", resp.json_body["message"])
self._set_use_vcenter(self.cluster)
resp = self.app.put(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': self.cluster['id']}),
params=jsonutils.dumps({
"editable": {
"metadata": {},
"value": {"foo": "bar"}
}
}),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(400, resp.status_code)
self.assertEqual(
"Metadata shouldn't change", resp.json_body["message"])
def test_404_if_no_attributes(self):
cluster = self.env.create_cluster(api=False)
self._set_use_vcenter(cluster)
self.db.delete(cluster.vmware_attributes)
self.db.commit()
resp = self.app.put(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': cluster.id}),
params=jsonutils.dumps({
"editable": {
"value": {"foo": "bar"}
}
}),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(404, resp.status_code)
def test_not_acceptable_if_cluster_has_not_support_vmware(self):
resp = self.app.get(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': self.cluster['id']}),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(400, resp.status_code)
self.assertEqual(
"Cluster doesn't support vmware configuration",
resp.json_body["message"]
)
resp = self.app.put(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': self.cluster['id']}),
params=jsonutils.dumps({
"editable": {
"value": {"foo": "bar"}
}
}),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(400, resp.status_code)
self.assertEqual(
"Cluster doesn't support vmware configuration",
resp.json_body["message"]
)
@patch('nailgun.db.sqlalchemy.models.Cluster.is_locked', return_value=True)
def test_vmware_attributes_update_for_locked_cluster_403(self, locked):
self._set_use_vcenter(self.cluster)
resp = self.app.put(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': self.cluster.id}),
params=jsonutils.dumps({
"editable": {
"value": {"foo": "bar"}
}
}),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(403, resp.status_code)
self.assertEqual("Environment attributes can't be changed after or "
"during deployment.", resp.json_body["message"])
@patch('objects.Cluster.has_compute_vmware_changes', return_value=True)
@patch('nailgun.db.sqlalchemy.models.Cluster.is_locked', return_value=True)
def test_vmware_attributes_update_for_locked_cluster_200(
self, is_locked_mock, has_compute_mock):
self._set_use_vcenter(self.cluster)
params = {
"editable": {
"value": {"foo": "bar"}
}}
with patch('nailgun.api.v1.handlers.cluster.VmwareAttributesHandler.'
'checked_data', return_value=params):
resp = self.app.put(
reverse(
'VmwareAttributesHandler',
kwargs={'cluster_id': self.cluster.id}),
params=jsonutils.dumps(params),
headers=self.default_headers
)
self.assertEqual(200, resp.status_code)
attrs = objects.Cluster.get_vmware_attributes(self.cluster)
self.assertEqual('bar', attrs.editable.get('value', {}).get('foo'))
attrs.editable.get('value', {}).pop('foo')
self.assertEqual(attrs.editable.get('value'), {})
def _set_use_vcenter(self, cluster):
cluster_attrs = objects.Cluster.get_editable_attributes(cluster)
cluster_attrs['common']['use_vcenter']['value'] = True
objects.Cluster.update_attributes(
cluster, {'editable': cluster_attrs})
class TestVmwareAttributesDefaults(BaseIntegrationTest):
def test_get_default_vmware_attributes(self):
cluster = self.env.create_cluster(api=True)
cluster_attrs = objects.Cluster.get_editable_attributes(cluster)
cluster_attrs['common']['use_vcenter']['value'] = True
objects.Cluster.update_attributes(
cluster, {'editable': cluster_attrs})
resp = self.app.get(
reverse(
'VmwareAttributesDefaultsHandler',
kwargs={'cluster_id': cluster['id']}),
headers=self.default_headers
)
release = objects.Release.get_by_uid(cluster['release_id'])
self.assertEqual(200, resp.status_code)
self.assertEqual(
release.vmware_attributes_metadata,
jsonutils.loads(resp.testbody)
)
def test_not_acceptable_if_cluster_has_not_support_vmware(self):
cluster = self.env.create_cluster(api=True)
resp = self.app.get(
reverse(
'VmwareAttributesDefaultsHandler',
kwargs={'cluster_id': cluster['id']}),
headers=self.default_headers,
expect_errors=True
)
self.assertEqual(400, resp.status_code)
self.assertEqual(
"Cluster doesn't support vmware configuration",
resp.json_body["message"]
)
class TestAttributesWithPlugins(BaseIntegrationTest):
def setUp(self):

View File

@ -38,12 +38,8 @@ class TestClusterChanges(BaseIntegrationTest):
name="networks"
).all()
self.assertEqual(len(networks_changes), 1)
vmware_changes = self.db.query(ClusterChanges).filter_by(
name="vmware_attributes"
).all()
self.assertEqual(len(vmware_changes), 1)
all_changes = self.db.query(ClusterChanges).all()
self.assertEqual(len(all_changes), 3)
self.assertEqual(len(all_changes), 2)
def test_node_volumes_modification_adds_pending_changes(self):
cluster = self.env.create_cluster(api=True)
@ -162,16 +158,12 @@ class TestClusterChanges(BaseIntegrationTest):
name="networks"
).all()
self.assertEqual(len(networks_changes), 1)
vmware_changes = self.db.query(ClusterChanges).filter_by(
name="vmware_attributes"
).all()
self.assertEqual(len(vmware_changes), 1)
disks_changes = self.db.query(ClusterChanges).filter_by(
name="disks"
).all()
self.assertEqual(len(disks_changes), 1)
all_changes = self.db.query(ClusterChanges).all()
self.assertEqual(len(all_changes), 5)
self.assertEqual(len(all_changes), 4)
@mock_rpc()
def test_role_unassignment_drops_changes(self):

View File

@ -149,7 +149,6 @@ class TestHandlers(BaseIntegrationTest):
}
}
}
release.vmware_attributes_metadata = {}
self.db.add(release)
self.db.commit()
resp = self.app.post(

View File

@ -2433,138 +2433,6 @@ class BaseDeploymentSerializer(BaseSerializerTest):
self.env.nodes[0], 'role')['user_node_name'],
self.node_name)
def check_generate_test_vm_image_data(self):
img_name = 'TestVM-VMDK'
disk_format = 'vmdk'
img_path = '/opt/vm/cirros-i386-disk.vmdk'
properties_data = {
'vmware_disktype': 'sparse',
'vmware_adaptertype': 'lsiLogic',
'hypervisor_type': 'vmware'
}
glance_properties = []
for k, v in six.iteritems(properties_data):
glance_properties.append('--property {k}={v}'.format(k=k, v=v))
self.assertEqual(
len(self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image']), 2)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][0]['img_name'],
img_name)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][0]['disk_format'],
disk_format)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][0]['img_path'],
img_path)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][0]['glance_properties'],
' '.join(glance_properties))
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][0]['properties'],
properties_data)
def check_generate_vmware_attributes_data(self):
cluster_db = self.db.query(Cluster).get(self.cluster['id'])
cluster_attrs = objects.Cluster.get_editable_attributes(cluster_db)
cluster_attrs.get('common', {}).setdefault('use_vcenter', {})
cluster_attrs['common']['use_vcenter']['value'] = True
objects.Cluster.update_attributes(
cluster_db, {'editable': cluster_attrs})
setattr(
cluster_db.vmware_attributes,
'editable',
self.vm_data[0]['editable'])
self.db.flush()
result = self.serializer.serialize_node(
self.env.nodes[0], 'controller'
)
self.assertEqual(len(result['vcenter']['computes']), 4)
self.assertIn(
result['vcenter']['computes'][0]['service_name'],
['Compute 1', 'Compute 3'])
self.assertIn(
result['vcenter']['computes'][1]['service_name'],
['Compute 1', 'Compute 3'])
# check compute parameters
self.assertEqual(
result['vcenter']['computes'][0]['availability_zone_name'],
"Zone 1")
self.assertEqual(
result['vcenter']['computes'][0]['vc_host'],
"1.2.3.4")
self.assertEqual(
result['vcenter']['computes'][0]['vc_user'],
"admin")
self.assertEqual(
result['vcenter']['computes'][0]['vc_password'],
"secret")
self.assertTrue(result['vcenter']['computes'][0]['vc_insecure'])
self.assertEqual(
result['vcenter']['computes'][0]['vc_ca_file'],
"file_blob")
self.assertEqual(
result['vcenter']['computes'][0]['vc_cluster'],
"cluster1")
# Be sure that "$" was converted to "$$"
self.assertEqual(
result['vcenter']['computes'][2]['vc_user'],
"user$$")
self.assertEqual(
result['vcenter']['computes'][2]['vc_password'],
"pass$$word")
self.assertEqual(
result['vcenter']['computes'][2]['datastore_regex'],
"^openstack-[0-9]$$")
self.assertTrue(result['use_vcenter'])
self.assertEqual(result['vcenter']['esxi_vlan_interface'], "eth0")
# check cinder parameters
self.assertEqual(len(result['cinder']['instances']), 2)
self.assertEqual(
result['cinder']['instances'][0]['availability_zone_name'],
"Zone 1")
self.assertEqual(
result['cinder']['instances'][0]['vc_host'],
"1.2.3.4")
self.assertEqual(
result['cinder']['instances'][0]['vc_user'],
"admin")
self.assertEqual(
result['cinder']['instances'][0]['vc_password'],
"secret")
self.assertTrue(result['cinder']['instances'][0]['vc_insecure'])
self.assertEqual(
result['cinder']['instances'][0]['vc_ca_file'],
"file_blob")
self.assertEqual(result['glance']['vc_host'], "1.2.3.4")
self.assertEqual(result['glance']['vc_user'], "admin")
self.assertEqual(result['glance']['vc_password'], "secret")
self.assertEqual(result['glance']['vc_datacenter'], "test_datacenter")
self.assertEqual(result['glance']['vc_datastore'], "test_datastore")
self.assertTrue(result['glance']['vc_insecure'])
self.assertEqual(result['glance']['vc_ca_file'], "file_blob")
def check_no_murano_data(self):
glance_properties = self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image']['glance_properties']
@ -2629,7 +2497,6 @@ class TestDeploymentMultinodeSerializer61(BaseDeploymentSerializer):
self.cluster = self.create_env(consts.CLUSTER_MODES.multinode)
objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
self.serializer = DeploymentMultinodeSerializer61(self.cluster)
self.vm_data = self.env.read_fixtures(['vmware_attributes'])
def test_serialize_node(self):
self.check_serialize_node()
@ -2637,9 +2504,6 @@ class TestDeploymentMultinodeSerializer61(BaseDeploymentSerializer):
def test_serialize_node_for_node_list(self):
self.check_serialize_node_for_node_list()
def test_generate_vmware_attributes_data(self):
self.check_generate_vmware_attributes_data()
def test_glance_properties(self):
self.check_no_murano_data()
@ -2698,35 +2562,16 @@ class TestDeploymentHASerializer61(BaseDeploymentSerializer):
self.cluster = self.create_env(consts.CLUSTER_MODES.ha_compact)
objects.Cluster.prepare_for_deployment(self.env.clusters[-1])
self.serializer = DeploymentHASerializer61(self.cluster)
self.vm_data = self.env.read_fixtures(['vmware_attributes'])
def check_generate_test_vm_image_data(self):
kvm_img_name = 'TestVM'
kvm_img_disk_format = 'qcow2'
kvm_img_path = '/opt/vm/cirros-x86_64-disk.img'
vmdk_img_name = 'TestVM-VMDK'
vmdk_disk_format = 'vmdk'
vmdk_img_path = '/opt/vm/cirros-i386-disk.vmdk'
self.assertEqual(
len(self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image']), 2)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][0]['img_name'],
vmdk_img_name)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][0]['disk_format'],
vmdk_disk_format)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][0]['img_path'],
vmdk_img_path)
self.assertEqual(
self.serializer.generate_test_vm_image_data(
self.env.nodes[0])['test_vm_image'][1]['img_name'],
@ -2748,19 +2593,6 @@ class TestDeploymentHASerializer61(BaseDeploymentSerializer):
def test_serialize_node_for_node_list(self):
self.check_serialize_node_for_node_list()
def test_generate_test_vm_image_data(self):
cluster_db = self.db.query(Cluster).get(self.cluster['id'])
cluster_attrs = objects.Cluster.get_editable_attributes(cluster_db)
cluster_attrs['common'].setdefault('use_vcenter', {})
cluster_attrs['common']['use_vcenter']['value'] = True
objects.Cluster.update_attributes(
cluster_db, {'editable': cluster_attrs})
self.check_generate_test_vm_image_data()
def test_generate_vmware_attributes_data(self):
self.check_generate_vmware_attributes_data()
def test_glance_properties(self):
self.check_no_murano_data()

View File

@ -266,7 +266,6 @@ class BaseTestDeploymentAttributesSerialization70(BaseDeploymentSerializer,
self.cluster_db, self.cluster_db.nodes)
self.serialized_for_astute = deployment_info_to_legacy(
self.serialized_for_astute)
self.vm_data = self.env.read_fixtures(['vmware_attributes'])
def create_env(self, mode):
release = self.patch_net_roles_for_release()
@ -507,20 +506,6 @@ class TestDeploymentAttributesSerialization70(
self.assertEqual(v['network_roles'], dict(network_roles))
self.check_vips_serialized(node_data)
def test_generate_vmware_attributes_data(self):
self.check_generate_vmware_attributes_data()
result = self.serializer.serialize_node(
self.env.nodes[0], 'compute-vmware'
)
self.assertEqual(
result['vcenter']['computes'][0]['target_node'],
"test_target_node")
self.assertEqual(
result['vcenter']['computes'][2]['target_node'],
"controllers")
class TestDeploymentAttributesSerializationSegmentationGre70(
TestDeploymentAttributesSerialization70
@ -670,20 +655,6 @@ class TestDeploymentSerializationForNovaNetwork70(
)
self.check_vips_serialized(node_data)
def test_generate_vmware_attributes_data(self):
self.check_generate_vmware_attributes_data()
result = self.serializer.serialize_node(
self.env.nodes[0], 'compute-vmware'
)
self.assertEqual(
result['vcenter']['computes'][0]['target_node'],
"test_target_node")
self.assertEqual(
result['vcenter']['computes'][2]['target_node'],
"controllers")
class TestPluginDeploymentTasksInjection70(base.BaseIntegrationTest):
env_version = '2015.1.0-7.0'

View File

@ -22,7 +22,6 @@ from nailgun import consts
from nailgun.db.sqlalchemy import models
from nailgun.objects import Cluster
from nailgun.objects import ReleaseCollection
from nailgun.objects import VmwareAttributes
from nailgun.settings import settings
from nailgun.statistics.fuel_statistics.installation_info \
import InstallationInfo
@ -128,29 +127,6 @@ class TestInstallationInfo(BaseTestCase):
result = info.get_attributes(attrs, info.attributes_white_list)
self.assertDictEqual({}, result)
def test_clusters_info_no_vmware_attributes_exception(self):
self.env.upload_fixtures(['openstack'])
info = InstallationInfo()
release = ReleaseCollection.filter_by(
None, operating_system=consts.RELEASE_OS.ubuntu)
nodes_params = [
{'roles': ['compute']},
{'roles': ['compute']},
{'roles': ['controller']}
]
cluster = self.env.create(
cluster_kwargs={
'release_id': release[0].id,
'mode': consts.CLUSTER_MODES.ha_compact,
'net_provider': consts.CLUSTER_NET_PROVIDERS.neutron},
nodes_kwargs=nodes_params
)
self.env.create_node(
{'status': consts.NODE_STATUSES.discover})
VmwareAttributes.delete(cluster.vmware_attributes)
self.env.db.flush()
self.assertNotRaises(AttributeError, info.get_clusters_info)
def test_clusters_info(self):
self.env.upload_fixtures(['openstack'])
info = InstallationInfo()
@ -433,7 +409,6 @@ class TestInstallationInfo(BaseTestCase):
('syslog', 'syslog_server'), ('workloads_collector', 'password'),
('workloads_collector', 'tenant'),
('workloads_collector', 'user'),
('common', 'use_vcenter'), # removed attribute
('murano_settings', 'murano_repo_url'),
('use_fedora_lt', 'kernel'),
('public_ssl', 'cert_data'), ('public_ssl', 'hostname'),
@ -468,25 +443,6 @@ class TestInstallationInfo(BaseTestCase):
for path in expected_paths:
self.assertIn(path, actual_paths)
def test_all_cluster_vmware_attributes_in_white_list(self):
cluster = self.env.create(nodes_kwargs=[{'roles': ['compute']}])
self.env.create_node(status=consts.NODE_STATUSES.discover)
expected_paths = self._find_leafs_paths(
cluster.vmware_attributes.editable,
leafs_names=('vsphere_cluster', 'enable'))
# Removing leaf name from expected paths
actual_paths = [rule.path[:-1] for rule in
InstallationInfo.vmware_attributes_white_list]
# If test failed here it means, that you have added cluster vmware
# attributes and they are not added into
# InstallationInfo.vmware_attributes_white_list
# If you don't know what should be added into white list, contact
# fuel-stats team please.
for path in expected_paths:
self.assertIn(path, actual_paths)
def test_all_plugin_data_collected(self):
cluster = self.env.create_cluster(api=False)
self.env.create_plugin(api=False, cluster=cluster)
@ -552,7 +508,6 @@ class TestInstallationInfo(BaseTestCase):
def test_white_list_unique_names(self):
white_list_attrs = (
'attributes_white_list',
'vmware_attributes_white_list',
'plugin_info_white_list',
'node_info_white_list'
)

View File

@ -55,8 +55,7 @@ JSON_TASKS = [
'type': 'puppet',
'version': '2.0.0',
'groups': ['primary-controller', 'controller', 'compute',
'compute-vmware', 'cinder', 'cinder-vmware',
'primary-mongo', 'mongo', 'ceph-osd', 'virt'],
'cinder', 'primary-mongo', 'mongo', 'ceph-osd', 'virt'],
'requires': ['firewall'],
'condition': "(settings:public_ssl.horizon.value == true or settings:"
"public_ssl.services.value == true) and settings:"
@ -124,8 +123,7 @@ EXPECTED_TASKS = [
'type': 'puppet',
'version': '2.0.0',
'groups': ['primary-controller', 'controller', 'compute',
'compute-vmware', 'cinder', 'cinder-vmware',
'primary-mongo', 'mongo', 'ceph-osd', 'virt'],
'cinder', 'primary-mongo', 'mongo', 'ceph-osd', 'virt'],
'requires': ['firewall'],
'condition': "(settings:public_ssl.horizon.value == true or "
"settings:public_ssl.services.value == true) "

View File

@ -1500,27 +1500,6 @@ class TestClusterObject(BaseTestCase):
'cluster': {u'net_provider': u'test_provider'}}
)
def test_cluster_has_compute_vmware_changes(self):
cluster = self.env.create_cluster(api=False)
ready_compute_vmware_node = self.env.create_node(
cluster_id=cluster.id,
roles=['compute-vmware'],
status=consts.NODE_STATUSES.ready
)
self.env.create_node(cluster_id=cluster.id, pending_addition=True,
pending_roles=['controller'])
self.assertFalse(objects.Cluster.has_compute_vmware_changes(cluster))
pending_compute_vmware_node = self.env.create_node(
cluster_id=cluster.id,
pending_roles=["compute-vmware"]
)
self.assertTrue(objects.Cluster.has_compute_vmware_changes(cluster))
objects.Node.delete(pending_compute_vmware_node)
objects.Node.update(
ready_compute_vmware_node, {'pending_deletion': True})
self.assertTrue(objects.Cluster.has_compute_vmware_changes(cluster))
def test_enable_settings_by_components(self):
components = [{
'name': 'network:neutron:tun',

View File

@ -19,13 +19,11 @@ import yaml
from nailgun import errors
from nailgun import objects
from nailgun.settings import settings
from nailgun.test import base
from nailgun.utils.restrictions import AttributesRestriction
from nailgun.utils.restrictions import ComponentsRestrictions
from nailgun.utils.restrictions import LimitsMixin
from nailgun.utils.restrictions import RestrictionBase
from nailgun.utils.restrictions import VmwareAttributesRestriction
DATA = """
@ -336,148 +334,6 @@ class TestAttributesRestriction(base.BaseTestCase):
self.assertListEqual(errs, [])
class TestVmwareAttributesRestriction(base.BaseTestCase):
def setUp(self):
super(TestVmwareAttributesRestriction, self).setUp()
self.cluster = self.env.create(
cluster_kwargs={
'api': False
}
)
self.vm_data = self.env.read_fixtures(['vmware_attributes'])[0]
def _get_models(self, attributes, vmware_attributes):
return {
'settings': attributes,
'default': vmware_attributes['editable'],
'current_vcenter': vmware_attributes['editable']['value'].get(
'availability_zones')[0],
'glance': vmware_attributes['editable']['value'].get('glance'),
'cluster': self.cluster,
'version': settings.VERSION,
'networking_parameters': self.cluster.network_config
}
def test_check_data_with_empty_values_without_restrictions(self):
attributes = objects.Cluster.get_editable_attributes(self.cluster)
attributes['common']['use_vcenter']['value'] = True
attributes['storage']['images_vcenter']['value'] = True
vmware_attributes = self.vm_data.copy()
empty_values = {
"availability_zones": [
{
"az_name": "",
"vcenter_host": "",
"vcenter_username": "",
"vcenter_password": "",
"vcenter_security_disabled": "",
"vcenter_ca_file": {},
"nova_computes": [
{
"vsphere_cluster": "",
"service_name": "",
"datastore_regex": ""
}
]
}
],
"network": {
"esxi_vlan_interface": ""
},
"glance": {
"vcenter_host": "",
"vcenter_username": "",
"vcenter_password": "",
"datacenter": "",
"datastore": "",
"vcenter_security_disabled": "",
"ca_file": {}
}
}
# Update value with empty value
vmware_attributes['editable']['value'] = empty_values
models = self._get_models(attributes, vmware_attributes)
errs = VmwareAttributesRestriction.check_data(
models=models,
metadata=vmware_attributes['editable']['metadata'],
data=vmware_attributes['editable']['value'])
self.assertItemsEqual(
errs,
['Empty cluster', 'Empty host', 'Empty username',
'Empty password', 'Empty datacenter', 'Empty datastore'])
def test_check_data_with_invalid_values_without_restrictions(self):
# Disable restrictions
attributes = objects.Cluster.get_editable_attributes(self.cluster)
attributes['common']['use_vcenter']['value'] = True
attributes['storage']['images_vcenter']['value'] = True
# value data taken from fixture one cluster of
# nova computes left empty
vmware_attributes = self.vm_data.copy()
models = self._get_models(attributes, vmware_attributes)
errs = VmwareAttributesRestriction.check_data(
models=models,
metadata=vmware_attributes['editable']['metadata'],
data=vmware_attributes['editable']['value'])
self.assertItemsEqual(errs, ['Empty cluster'])
def test_check_data_with_invalid_values_and_with_restrictions(self):
attributes = objects.Cluster.get_editable_attributes(self.cluster)
# fixture have restrictions enabled for glance that's why
# only 'Empty cluster' should returned
vmware_attributes = self.vm_data.copy()
models = self._get_models(attributes, vmware_attributes)
errs = VmwareAttributesRestriction.check_data(
models=models,
metadata=vmware_attributes['editable']['metadata'],
data=vmware_attributes['editable']['value'])
self.assertItemsEqual(errs, ['Empty cluster'])
def test_check_data_with_valid_values_and_with_restrictions(self):
attributes = objects.Cluster.get_editable_attributes(self.cluster)
vmware_attributes = self.vm_data.copy()
# Set valid data for clusters
for i, azone in enumerate(
vmware_attributes['editable']['value']['availability_zones']):
for j, ncompute in enumerate(azone['nova_computes']):
ncompute['vsphere_cluster'] = 'cluster-{0}-{1}'.format(i, j)
models = self._get_models(attributes, vmware_attributes)
errs = VmwareAttributesRestriction.check_data(
models=models,
metadata=vmware_attributes['editable']['metadata'],
data=vmware_attributes['editable']['value'])
self.assertItemsEqual(errs, [])
def test_check_data_with_valid_values_and_without_restrictions(self):
# Disable restrictions
attributes = objects.Cluster.get_editable_attributes(self.cluster)
attributes['common']['use_vcenter']['value'] = True
attributes['storage']['images_vcenter']['value'] = True
vmware_attributes = self.vm_data.copy()
# Set valid data for clusters
for i, azone in enumerate(
vmware_attributes['editable']['value']['availability_zones']):
for j, ncompute in enumerate(azone['nova_computes']):
ncompute['vsphere_cluster'] = 'cluster-{0}-{1}'.format(i, j)
# Set valid data for glance
glance = vmware_attributes['editable']['value']['glance']
glance['datacenter'] = 'test_datacenter'
glance['datastore'] = 'test_datastore'
models = self._get_models(attributes, vmware_attributes)
errs = VmwareAttributesRestriction.check_data(
models=models,
metadata=vmware_attributes['editable']['metadata'],
data=vmware_attributes['editable']['value'])
self.assertItemsEqual(errs, [])
class TestComponentsRestrictions(base.BaseTestCase):
def setUp(self):

View File

@ -614,96 +614,6 @@ class TestCheckBeforeDeploymentTask(BaseTestCase):
task.CheckBeforeDeploymentTask._check_public_network,
self.task)
def test_check_missed_nodes_vmware_nova_computes(self):
operational_node = self.env.create_node(
roles=['compute-vmware'],
cluster_id=self.cluster.id,
name='node-1'
)
pending_addition_node = self.env.create_node(
roles=['compute-vmware'],
cluster_id=self.cluster.id,
pending_addition=True,
name='node-2'
)
msg = ("The following compute-vmware nodes are not assigned to "
"any vCenter cluster: {0}").format(', '.join(
sorted([operational_node.name, pending_addition_node.name])
))
with self.assertRaisesRegexp(errors.CheckBeforeDeploymentError, msg):
task.CheckBeforeDeploymentTask._check_vmware_consistency(self.task)
@mock.patch('objects.VmwareAttributes.get_nova_computes_target_nodes')
def test_check_not_deleted_nodes_vmware_nova_computes(self, target_nodes):
operational_node = self.env.create_node(
roles=['compute-vmware'],
cluster_id=self.cluster.id,
name='node-1'
)
pending_deletion_node = self.env.create_node(
roles=['compute-vmware'],
cluster_id=self.cluster.id,
pending_deletion=True,
name='node-2'
)
target_nodes.return_value = [{
'id': operational_node.hostname,
'label': operational_node.name
}, {
'id': pending_deletion_node.hostname,
'label': pending_deletion_node.name
}]
msg = ("The following nodes are prepared for deletion and couldn't be "
"assigned to any vCenter cluster: {0}".format(
pending_deletion_node.name))
with self.assertRaisesRegexp(errors.CheckBeforeDeploymentError, msg):
task.CheckBeforeDeploymentTask._check_vmware_consistency(self.task)
@mock.patch('objects.VmwareAttributes.get_nova_computes_target_nodes')
def test_check_extra_nodes_vmware_nova_computes(self, target_nodes):
operational_node = self.env.create_node(
roles=['compute-vmware'],
cluster_id=self.cluster.id,
name='node-1'
)
non_cluster_node = self.env.create_node(
roles=['compute-vmware'],
name='node-2'
)
other_role_node = self.env.create_node(
cluster_id=self.cluster.id,
name='node-3'
)
target_nodes.return_value = [{
'id': operational_node.hostname,
'label': operational_node.name
}, {
'id': non_cluster_node.hostname,
'label': non_cluster_node.name
}, {
'id': other_role_node.hostname,
'label': other_role_node.name
}]
msg = ("The following nodes don't belong to compute-vmware nodes of "
"environment and couldn't be assigned to any vSphere cluster: "
"{0}".format(', '.join(
sorted([non_cluster_node.name, other_role_node.name]))
))
with self.assertRaisesRegexp(errors.CheckBeforeDeploymentError, msg):
task.CheckBeforeDeploymentTask._check_vmware_consistency(self.task)
@mock.patch.object(
task, 'fire_callback_on_before_deployment_check')
@mock.patch.object(
task.CheckBeforeDeploymentTask, '_check_sriov_properties')
@mock.patch.object(
task.CheckBeforeDeploymentTask, '_check_dpdk_properties')
def test_execute_w_old_release(self, dpdk_m, sriov_m, callback_m):
task.CheckBeforeDeploymentTask.execute(self.task)
callback_m.assert_called_once_with(self.cluster, [])
self.assertEqual(0, dpdk_m.call_count)
self.assertEqual(0, sriov_m.call_count)
class TestDeployTask(BaseTestCase):

View File

@ -1,443 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2015 Mirantis, Inc.
#
# 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.
from copy import deepcopy
from mock import patch
from nailgun.api.v1.validators.cluster import VmwareAttributesValidator
from nailgun import consts
from nailgun import errors
from nailgun import objects
from nailgun.test.base import BaseTestCase
class TestAttributesValidator(BaseTestCase):
def setUp(self):
super(TestAttributesValidator, self).setUp()
self.cluster = self.env.create(
cluster_kwargs={
"api": False,
"vmware_attributes": {
"editable": self._get_value_vmware_attributes()
}
},
nodes_kwargs=[{
"hostname": "controller-node",
"status": consts.NODE_STATUSES.ready
}]
)
self.ready_compute_node = self.env.create_node(
hostname="node-1",
name="Node 1",
roles=["compute-vmware"],
status=consts.NODE_STATUSES.ready,
cluster_id=self.cluster.id
)
def _get_target_id(self, nova_compute):
return nova_compute["target_node"]["current"]["id"]
def _get_default_nova_computes(self):
return [
{
"datastore_regex": ".*",
"vsphere_cluster": "Cluster1",
"target_node": {
"current": {
"id": "node-1",
"label": "node-1"
}
},
"service_name": "ns1"
},
{
"datastore_regex": ".*",
"vsphere_cluster": "Cluster0",
"target_node": {
"current": {
"id": "controllers",
"label": "controllers"
}
},
"service_name": "ns0"
}
]
def _get_value_vmware_attributes(self, nova_computes=None):
return {
"value": {
"availability_zones": [{
"vcenter_username": "admin",
"az_name": "vcenter",
"vcenter_password": "pass",
"vcenter_host": "172.16.0.254",
"nova_computes":
nova_computes or self._get_default_nova_computes()
}]
}
}
def validate_nova_compute_raises_regexp(self, nova_computes, error_msg):
with self.assertRaisesRegexp(errors.InvalidData, error_msg):
VmwareAttributesValidator._validate_nova_computes(
{"editable": self._get_value_vmware_attributes(nova_computes)},
self.cluster.vmware_attributes
)
def test_change_exist_nova_compute(self):
nova_computes = self._get_default_nova_computes()
changed_attribute = 'vsphere_cluster'
for nc in nova_computes:
if self._get_target_id(nc) == self.ready_compute_node.hostname:
nc[changed_attribute] = "ClusterXX"
break
self.validate_nova_compute_raises_regexp(
nova_computes,
"Parameter '{0}' of nova compute instance with target node '{1}' "
"couldn't be changed".format(
changed_attribute, self.ready_compute_node.name
)
)
def test_delete_operational_nova_compute_node(self):
nova_computes = [
nc for nc in self._get_default_nova_computes() if
self._get_target_id(nc) != self.ready_compute_node.hostname
]
self.validate_nova_compute_raises_regexp(
nova_computes,
"The following compute-vmware node couldn't be deleted from "
"vSphere cluster: {0}".format(self.ready_compute_node.name)
)
def test_duplicate_values_for_nova_computes(self):
for attr in ("vsphere_cluster", "target_node", "service_name"):
exist_nova_computes = self._get_default_nova_computes()
duplicate_value = exist_nova_computes[0][attr]
new_nova_compute = {
"datastore_regex": ".*",
"vsphere_cluster": "ClusterXX",
"target_node": {
"current": {
"id": "node-X",
"label": "node-X"
},
},
"service_name": "nsXX"
}
new_nova_compute.update({attr: duplicate_value})
exist_nova_computes.append(new_nova_compute)
duplicate_value = duplicate_value if attr != "target_node" \
else duplicate_value["current"]["id"]
self.validate_nova_compute_raises_regexp(
exist_nova_computes,
"Duplicate value '{0}' for attribute '{1}' is not allowed".
format(duplicate_value, attr)
)
def test_empty_values_for_nova_computes(self):
nova_computes = self._get_default_nova_computes()
nova_computes[0]["vsphere_cluster"] = ""
self.validate_nova_compute_raises_regexp(
nova_computes,
"Empty value for attribute 'vsphere_cluster' is not allowed"
)
def test_nova_compute_setting_validate_pass(self):
new_compute_vmware_node = self.env.create_node(
hostname="node-2",
name="Node 2",
pending_roles=["compute-vmware"],
pending_addition=True,
cluster_id=self.cluster.id
)
self.env.create_node(
hostname="node-3",
name="Node 3",
roles=["compute-vmware"],
pending_deletion=True,
cluster_id=self.cluster.id
)
attributes = self.cluster.vmware_attributes
new_nova_computes = self._get_default_nova_computes()
new_nova_computes.extend([{
"datastore_regex": ".*",
"vsphere_cluster": "Cluster2",
"target_node": {
"current": {
"id": new_compute_vmware_node.hostname,
"label": new_compute_vmware_node.name
}
},
"service_name": "ns2"
}])
self.assertNotRaises(errors.InvalidData,
VmwareAttributesValidator._validate_nova_computes,
{"editable": self._get_value_vmware_attributes(
new_nova_computes)},
attributes)
def test_change_controller_nova_computes_pass(self):
cluster = self.env.create(
cluster_kwargs={
"api": False,
"status": consts.CLUSTER_STATUSES.new,
"vmware_attributes": {
"editable": self._get_value_vmware_attributes()
}
}
)
new_nova_computes = [nc for nc in self._get_default_nova_computes()
if self._get_target_id(nc) == "controllers"]
new_nova_computes[0]["vsphere_cluster"] = "new vsphere name"
new_nova_computes.append({
"datastore_regex": ".*",
"vsphere_cluster": "Cluster10",
"target_node": {
"current": {
"id": "controllers",
"label": "controllers"
}
},
"service_name": "ns10"
})
self.assertNotRaises(errors.InvalidData,
VmwareAttributesValidator._validate_nova_computes,
{"editable": self._get_value_vmware_attributes(
new_nova_computes)},
cluster.vmware_attributes)
@patch("nailgun.db.sqlalchemy.models.Cluster.is_locked", return_value=True)
def test_change_controllers_nova_compute_setting(self, lock_mock):
new_nova_computes = self._get_default_nova_computes()
changed_vsphere_cluster = None
changed_attribute = "service_name"
for nc in new_nova_computes:
if self._get_target_id(nc) == "controllers":
nc[changed_attribute] = "new_service_name"
changed_vsphere_cluster = nc
break
self.validate_nova_compute_raises_regexp(
new_nova_computes,
"Parameter '{0}' of nova compute instance with vSphere cluster "
"name '{1}' couldn't be changed".format(
changed_attribute, changed_vsphere_cluster["vsphere_cluster"])
)
@patch("nailgun.db.sqlalchemy.models.Cluster.is_locked", return_value=True)
def test_add_controllers_nova_compute_setting(self, lock_mock):
new_nova_computes = self._get_default_nova_computes()
new_nova_computes.extend([{
"datastore_regex": ".*",
"vsphere_cluster": "Cluster20",
"target_node": {
"current": {
"id": "controllers",
"label": "controllers"
}
},
"service_name": "ns20"
}, {
"datastore_regex": ".*",
"vsphere_cluster": "Cluster30",
"target_node": {
"current": {
"id": "controllers",
"label": "controllers"
}
},
"service_name": "ns30"
}])
self.validate_nova_compute_raises_regexp(
new_nova_computes,
"Nova compute instances with target 'controllers' couldn't be "
"added to operational environment. Check nova compute instances "
"with the following vSphere cluster names: {0}".format(
", ".join(sorted(["Cluster30", "Cluster20"]))
)
)
@patch("nailgun.db.sqlalchemy.models.Cluster.is_locked", return_value=True)
def test_remove_controllers_nova_compute_setting(self, lock_mock):
new_nova_computes = [nc for nc in self._get_default_nova_computes()
if self._get_target_id(nc) != "controllers"]
self.validate_nova_compute_raises_regexp(
new_nova_computes,
"Nova compute instance with target 'controllers' and vSphere "
"cluster {0} couldn't be deleted from operational environment."
.format("Cluster0")
)
def test_update_non_editable_attributes(self):
metadata = [
{
"name": "foo",
"label": "foo",
"type": "object",
"fields": [{
"name": "foo_field_name",
"label": "foo_field_name",
}]
}, {
"name": "availability_zones",
"label": "availability_zones",
"type": "array",
"fields": [{
"name": "az_name",
"label": "az_name",
}, {
"name": "nova_computes",
"type": "array",
"fields": [{
"name": "vsphere_cluster",
"label": "vsphere_cluster",
}, {
"name": "target_node",
"label": "target_node",
}]
}, {
"name": "vcenter_host",
"label": "vcenter_host",
}]
}
]
db_attributes_value = {
"availability_zones": [{
"az_name": "az_1",
"vcenter_host": "127.0.0.1",
"nova_computes": [{
"vsphere_cluster": "Cluster1",
"target_node": {
"current": {"id": "node-1"}
}
}]
}],
"foo": {
"foo_field_name": "foo_field_value"
}
}
instance = objects.VmwareAttributes.create(
{"editable": {"metadata": metadata, "value": db_attributes_value}}
)
new_attributes = deepcopy(db_attributes_value)
new_attributes["foo"] = ["foo_field_name"]
msg = "Value type of 'foo_field_name' attribute couldn't be changed."
with self.assertRaisesRegexp(errors.InvalidData, msg):
VmwareAttributesValidator._validate_updated_attributes(
{"editable": {"value": new_attributes}},
instance)
new_attributes = deepcopy(db_attributes_value)
new_attributes["foo"]["foo_field_name"] = "new_foo_field_value"
msg = "Value of 'foo_field_name' attribute couldn't be changed."
with self.assertRaisesRegexp(errors.InvalidData, msg):
VmwareAttributesValidator._validate_updated_attributes(
{"editable": {"value": new_attributes}},
instance)
new_attributes = deepcopy(db_attributes_value)
new_attributes["availability_zones"].append({
"az_name": "az_2",
"vcenter_host": "127.0.0.1",
"nova_computes": []
})
msg = "Value of 'availability_zones' attribute couldn't be changed."
with self.assertRaisesRegexp(errors.InvalidData, msg):
VmwareAttributesValidator._validate_updated_attributes(
{"editable": {"value": new_attributes}}, instance)
new_attributes = deepcopy(db_attributes_value)
new_attributes["availability_zones"][0]["nova_computes"][0].update(
{"target_node": {"current": {"id": "node-2"}}}
)
msg = "Value of 'target_node' attribute couldn't be changed."
with self.assertRaisesRegexp(errors.InvalidData, msg):
VmwareAttributesValidator._validate_updated_attributes(
{"editable": {"value": new_attributes}}, instance)
def test_update_editable_attributes(self):
metadata = [
{
"name": "foo",
"label": "foo",
"type": "object",
"editable_for_deployed": True,
"fields": [{
"name": "foo_field_name",
"label": "foo_field_name",
}]
}, {
"name": "availability_zones",
"type": "array",
"label": "availability_zones",
"fields": [{
"name": "az_name",
"label": "az_name",
}, {
"name": "nova_computes",
"editable_for_deployed": True,
"type": "array",
"fields": [{
"name": "vsphere_cluster",
"label": "vsphere_cluster",
}, {
"name": "target_node",
"label": "target_node",
}]
}, {
"name": "vcenter_host",
"label": "vcenter_host",
}]
}
]
db_attributes_value = {
"availability_zones": [{
"az_name": "az_1",
"vcenter_host": "127.0.0.1",
"nova_computes": [{
"vsphere_cluster": "Cluster1",
"target_node": {
"current": {"id": "node-1"}
}
}]
}],
"foo": {
"foo_field_name": "foo_field_value"
}
}
instance = objects.VmwareAttributes.create(
{"editable": {"metadata": metadata, "value": db_attributes_value}}
)
new_attributes = deepcopy(db_attributes_value)
new_attributes["foo"]["foo_field_name"] = 1
new_attributes["availability_zones"][0]["nova_computes"][0].update(
{"target_node": {"current": {"id": "node-2"}}}
)
new_attributes["availability_zones"][0]["nova_computes"].append({
"vsphere_cluster": "Cluster2",
"target_node": {
"current": {"id": "node-2"}
}
})
self.assertNotRaises(
errors.InvalidData,
VmwareAttributesValidator._validate_updated_attributes,
{"editable": {"value": new_attributes}},
instance)

View File

@ -25,7 +25,6 @@ import six
from nailgun import errors
from nailgun.expression import Expression
from nailgun.utils import camel_to_snake_case
from nailgun.utils import compact
from nailgun.utils import flatten
@ -396,86 +395,6 @@ class AttributesRestriction(RestrictionBase):
'items'.format(attr_value, max_items_num))
class VmwareAttributesRestriction(RestrictionBase):
@classmethod
def check_data(cls, models, metadata, data):
"""Check cluster vmware attributes data
:param models: objects which represent models in restrictions
:type models: dict
:param metadata: vmware attributes metadata object
:type metadata: list|dict
:param data: vmware attributes data(value) object
:type data: list|dict
:returns: func -- generator which produces errors
"""
root_key = camel_to_snake_case(cls.__name__)
def find_errors(metadata=metadata, path_key=root_key):
"""Generator for vmware attributes errors
for each attribute in 'metadata' gets relevant values from vmware
'value' and checks them with restrictions and regexs
"""
if isinstance(metadata, dict):
restr = cls.check_restrictions(
models, metadata.get('restrictions', []))
if restr.get('result'):
# TODO(apopovych): handle restriction message?
return
else:
for mkey, mvalue in six.iteritems(metadata):
if mkey == 'name':
value_path = path_key.replace(
root_key, '').replace('.fields', '')
values = cls._get_values(value_path, data)
attr_regex = metadata.get('regex', {})
if attr_regex:
pattern = re.compile(attr_regex.get('source'))
for value in values():
if not pattern.match(value):
yield attr_regex.get('error')
for err in find_errors(
mvalue, '.'.join([path_key, mkey])):
yield err
elif isinstance(metadata, list):
for i, item in enumerate(metadata):
current_key = item.get('name') or str(i)
for err in find_errors(
item, '.'.join([path_key, current_key])):
yield err
return list(find_errors())
@classmethod
def _get_values(cls, path, data):
"""Generator for all values from data selected by given path
:param path: path to all releted values
:type path: string
:param data: vmware attributes value
:type data: list|dict
"""
keys = path.split('.')
key = keys[-1]
def find(data=data):
if isinstance(data, dict):
for k, v in six.iteritems(data):
if k == key:
yield v
elif k in keys:
for result in find(v):
yield result
elif isinstance(data, list):
for d in data:
for result in find(d):
yield result
return find
class ComponentsRestrictions(object):
@classmethod