Fuel UI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cluster.py 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2013 Mirantis, Inc.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. from sqlalchemy import Boolean
  16. from sqlalchemy import Column
  17. from sqlalchemy import Enum
  18. from sqlalchemy import ForeignKey
  19. from sqlalchemy import Integer
  20. from sqlalchemy import String
  21. from sqlalchemy import Text
  22. from sqlalchemy import UnicodeText
  23. from sqlalchemy.dialects import postgresql as psql
  24. from sqlalchemy.orm import backref
  25. from sqlalchemy.orm import relationship
  26. from oslo_serialization import jsonutils
  27. from nailgun import consts
  28. from nailgun.db.sqlalchemy.models.base import Base
  29. from nailgun.db.sqlalchemy.models.fields import JSON
  30. from nailgun.db.sqlalchemy.models.mutable import MutableDict
  31. from nailgun.db.sqlalchemy.models.mutable import MutableList
  32. class ClusterChanges(Base):
  33. __tablename__ = 'cluster_changes'
  34. id = Column(Integer, primary_key=True)
  35. cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete='CASCADE'))
  36. node_id = Column(Integer, ForeignKey('nodes.id', ondelete='CASCADE'))
  37. name = Column(
  38. Enum(*consts.CLUSTER_CHANGES, name='possible_changes'),
  39. nullable=False
  40. )
  41. class Cluster(Base):
  42. __tablename__ = 'clusters'
  43. id = Column(Integer, primary_key=True)
  44. mode = Column(
  45. Enum(*consts.CLUSTER_MODES, name='cluster_mode'),
  46. nullable=False,
  47. default=consts.CLUSTER_MODES.ha_compact
  48. )
  49. status = Column(
  50. Enum(*consts.CLUSTER_STATUSES, name='cluster_status'),
  51. nullable=False,
  52. default=consts.CLUSTER_STATUSES.new
  53. )
  54. net_provider = Column(
  55. Enum(*consts.CLUSTER_NET_PROVIDERS, name='net_provider'),
  56. nullable=False,
  57. default=consts.CLUSTER_NET_PROVIDERS.neutron
  58. )
  59. network_config = relationship("NetworkingConfig",
  60. backref=backref("cluster"),
  61. cascade="all,delete",
  62. uselist=False)
  63. ui_settings = Column(
  64. MutableDict.as_mutable(JSON),
  65. nullable=False,
  66. server_default=jsonutils.dumps({
  67. "view_mode": "standard",
  68. "filter": {},
  69. "sort": [{"roles": "asc"}],
  70. "filter_by_labels": {},
  71. "sort_by_labels": [],
  72. "search": ""
  73. }),
  74. )
  75. name = Column(UnicodeText, unique=True, nullable=False)
  76. release_id = Column(Integer, ForeignKey('releases.id'), nullable=False)
  77. nodes = relationship(
  78. "Node", backref="cluster", cascade="delete", order_by='Node.id')
  79. tasks = relationship("Task", backref="cluster")
  80. plugin_links = relationship(
  81. "ClusterPluginLink", backref="cluster", cascade="delete")
  82. attributes = relationship("Attributes", uselist=False,
  83. backref="cluster", cascade="delete")
  84. changes_list = relationship("ClusterChanges", backref="cluster",
  85. cascade="delete")
  86. vmware_attributes = relationship("VmwareAttributes", uselist=False,
  87. backref="cluster", cascade="delete")
  88. # We must keep all notifications even if cluster is removed.
  89. # It is because we want user to be able to see
  90. # the notification history so that is why we don't use
  91. # cascade="delete" in this relationship
  92. # During cluster deletion sqlalchemy engine will set null
  93. # into cluster foreign key column of notification entity
  94. notifications = relationship("Notification", backref="cluster")
  95. node_groups = relationship(
  96. "NodeGroup",
  97. backref="cluster",
  98. cascade="delete"
  99. )
  100. replaced_deployment_info = Column(
  101. MutableDict.as_mutable(JSON), default={}
  102. )
  103. replaced_provisioning_info = Column(
  104. MutableDict.as_mutable(JSON), default={})
  105. is_customized = Column(Boolean, default=False)
  106. fuel_version = Column(Text, nullable=False)
  107. components = Column(
  108. MutableList.as_mutable(JSON),
  109. default=[],
  110. server_default='[]',
  111. nullable=False)
  112. extensions = Column(psql.ARRAY(String(consts.EXTENSION_NAME_MAX_SIZE)),
  113. default=[], nullable=False, server_default='{}')
  114. volumes_metadata = Column(MutableDict.as_mutable(JSON),
  115. default={},
  116. server_default='{}')
  117. roles_metadata = Column(MutableDict.as_mutable(JSON),
  118. default={},
  119. server_default='{}')
  120. tags_metadata = Column(MutableDict.as_mutable(JSON),
  121. server_default='{}',
  122. nullable=False)
  123. @property
  124. def changes(self):
  125. return [
  126. {"name": i.name, "node_id": i.node_id}
  127. for i in self.changes_list
  128. ]
  129. @changes.setter
  130. def changes(self, value):
  131. self.changes_list = value
  132. @property
  133. def is_ha_mode(self):
  134. return self.mode in ('ha_full', 'ha_compact')
  135. @property
  136. def full_name(self):
  137. return '%s (id=%s, mode=%s)' % (self.name, self.id, self.mode)
  138. @property
  139. def is_locked(self):
  140. allowed_status = (
  141. consts.CLUSTER_STATUSES.error,
  142. consts.CLUSTER_STATUSES.new,
  143. consts.CLUSTER_STATUSES.operational,
  144. consts.CLUSTER_STATUSES.stopped,
  145. consts.CLUSTER_STATUSES.partially_deployed
  146. )
  147. return self.status not in allowed_status
  148. @property
  149. def network_groups(self):
  150. net_list = []
  151. for ng in self.node_groups:
  152. net_list.extend(ng.networks)
  153. return net_list
  154. class Attributes(Base):
  155. __tablename__ = 'attributes'
  156. id = Column(Integer, primary_key=True)
  157. cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete='CASCADE'))
  158. editable = Column(MutableDict.as_mutable(JSON))
  159. generated = Column(MutableDict.as_mutable(JSON))
  160. class VmwareAttributes(Base):
  161. __tablename__ = 'vmware_attributes'
  162. id = Column(Integer, primary_key=True)
  163. cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete='CASCADE'))
  164. editable = Column(MutableDict.as_mutable(JSON))