models.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. # Copyright 2016 Cloudbase Solutions Srl
  2. # All Rights Reserved.
  3. import uuid
  4. from oslo_db.sqlalchemy import models
  5. import sqlalchemy
  6. from sqlalchemy.ext import declarative
  7. from sqlalchemy import orm
  8. from sqlalchemy import schema
  9. from coriolis import constants
  10. from coriolis.db.sqlalchemy import types
  11. BASE = declarative.declarative_base()
  12. MAX_EVENT_MESSAGE_LENGHT = 1024
  13. class TaskEvent(BASE, models.TimestampMixin, models.SoftDeleteMixin,
  14. models.ModelBase):
  15. __tablename__ = 'task_event'
  16. id = sqlalchemy.Column(sqlalchemy.String(36),
  17. default=lambda: str(uuid.uuid4()),
  18. primary_key=True)
  19. task_id = sqlalchemy.Column(sqlalchemy.String(36),
  20. sqlalchemy.ForeignKey('task.id'),
  21. nullable=False)
  22. level = sqlalchemy.Column(sqlalchemy.String(20), nullable=False)
  23. index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
  24. message = sqlalchemy.Column(
  25. sqlalchemy.String(MAX_EVENT_MESSAGE_LENGHT), nullable=False)
  26. def to_dict(self):
  27. result = {
  28. "id": self.id,
  29. "task_id": self.task_id,
  30. "level": self.level,
  31. "message": self.message,
  32. "index": self.index,
  33. "created_at": self.created_at,
  34. "updated_at": self.updated_at,
  35. "deleted_at": self.deleted_at,
  36. "deleted": self.deleted,
  37. }
  38. return result
  39. class MinionPoolEvent(BASE, models.TimestampMixin, models.SoftDeleteMixin,
  40. models.ModelBase):
  41. __tablename__ = 'minion_pool_event'
  42. id = sqlalchemy.Column(sqlalchemy.String(36),
  43. default=lambda: str(uuid.uuid4()),
  44. primary_key=True)
  45. pool_id = sqlalchemy.Column(sqlalchemy.String(36),
  46. sqlalchemy.ForeignKey('minion_pool.id'),
  47. nullable=False)
  48. level = sqlalchemy.Column(sqlalchemy.String(20), nullable=False)
  49. index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
  50. message = sqlalchemy.Column(sqlalchemy.Text, nullable=False)
  51. def to_dict(self):
  52. result = {
  53. "id": self.id,
  54. "pool_id": self.pool_id,
  55. "level": self.level,
  56. "index": self.index,
  57. "message": self.message,
  58. "created_at": self.created_at,
  59. "updated_at": self.updated_at,
  60. "deleted_at": self.deleted_at,
  61. "deleted": self.deleted,
  62. }
  63. return result
  64. class TaskProgressUpdate(BASE, models.TimestampMixin, models.SoftDeleteMixin,
  65. models.ModelBase):
  66. __tablename__ = 'task_progress_update'
  67. __table_args__ = (
  68. schema.UniqueConstraint("task_id", "index", "deleted"),)
  69. id = sqlalchemy.Column(sqlalchemy.String(36),
  70. default=lambda: str(uuid.uuid4()),
  71. primary_key=True)
  72. task_id = sqlalchemy.Column(sqlalchemy.String(36),
  73. sqlalchemy.ForeignKey('task.id'),
  74. nullable=False)
  75. index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
  76. current_step = sqlalchemy.Column(sqlalchemy.BigInteger, nullable=False)
  77. total_steps = sqlalchemy.Column(sqlalchemy.BigInteger, nullable=True)
  78. message = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
  79. def to_dict(self):
  80. result = {
  81. "id": self.id,
  82. "task_id": self.task_id,
  83. "index": self.index,
  84. "current_step": self.current_step,
  85. "total_steps": self.total_steps,
  86. "message": self.message,
  87. "created_at": self.created_at,
  88. "updated_at": self.updated_at,
  89. "deleted_at": self.deleted_at,
  90. "deleted": self.deleted,
  91. }
  92. return result
  93. class MinionPoolProgressUpdate(
  94. BASE, models.TimestampMixin, models.SoftDeleteMixin, models.ModelBase):
  95. __tablename__ = 'minion_pool_progress_update'
  96. __table_args__ = (
  97. schema.UniqueConstraint("pool_id", "index", "deleted"),)
  98. id = sqlalchemy.Column(sqlalchemy.String(36),
  99. default=lambda: str(uuid.uuid4()),
  100. primary_key=True)
  101. pool_id = sqlalchemy.Column(sqlalchemy.String(36),
  102. sqlalchemy.ForeignKey('minion_pool.id'),
  103. nullable=False)
  104. index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
  105. current_step = sqlalchemy.Column(sqlalchemy.BigInteger, nullable=False)
  106. total_steps = sqlalchemy.Column(sqlalchemy.BigInteger, nullable=True)
  107. message = sqlalchemy.Column(sqlalchemy.String(1024), nullable=True)
  108. def to_dict(self):
  109. result = {
  110. "id": self.id,
  111. "pool_id": self.pool_id,
  112. "index": self.index,
  113. "current_step": self.current_step,
  114. "total_steps": self.total_steps,
  115. "message": self.message,
  116. "created_at": self.created_at,
  117. "updated_at": self.updated_at,
  118. "deleted_at": self.deleted_at,
  119. "deleted": self.deleted,
  120. }
  121. return result
  122. class Task(BASE, models.TimestampMixin, models.SoftDeleteMixin,
  123. models.ModelBase):
  124. __tablename__ = 'task'
  125. id = sqlalchemy.Column(sqlalchemy.String(36),
  126. default=lambda: str(uuid.uuid4()),
  127. primary_key=True)
  128. execution_id = sqlalchemy.Column(
  129. sqlalchemy.String(36),
  130. sqlalchemy.ForeignKey('tasks_execution.id'), nullable=False)
  131. instance = sqlalchemy.Column(sqlalchemy.String(1024), nullable=False)
  132. host = sqlalchemy.Column(sqlalchemy.String(1024), nullable=True)
  133. process_id = sqlalchemy.Column(sqlalchemy.Integer, nullable=True)
  134. status = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
  135. task_type = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
  136. exception_details = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
  137. depends_on = sqlalchemy.Column(types.List, nullable=True)
  138. index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
  139. on_error = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False)
  140. # TODO(alexpilotti): Add soft delete filter
  141. events = orm.relationship(TaskEvent, cascade="all,delete",
  142. backref=orm.backref('task'),
  143. order_by=TaskEvent.index)
  144. # TODO(alexpilotti): Add soft delete filter
  145. progress_updates = orm.relationship(TaskProgressUpdate,
  146. cascade="all,delete",
  147. backref=orm.backref('task'),
  148. order_by=(
  149. TaskProgressUpdate.index))
  150. def to_dict(self):
  151. result = {
  152. "id": self.id,
  153. "execution_id": self.execution_id,
  154. "instance": self.instance,
  155. "host": self.host,
  156. "process_id": self.process_id,
  157. "status": self.status,
  158. "task_type": self.task_type,
  159. "exception_details": self.exception_details,
  160. "depends_on": self.depends_on,
  161. "index": self.index,
  162. "on_error": self.on_error,
  163. "events": [],
  164. "progress_updates": [],
  165. "created_at": self.created_at,
  166. "updated_at": self.updated_at,
  167. "deleted_at": self.deleted_at,
  168. "deleted": self.deleted,
  169. }
  170. for evt in self.events:
  171. result["events"].append(evt.to_dict())
  172. for pgu in self.progress_updates:
  173. result["progress_updates"].append(
  174. pgu.to_dict())
  175. return result
  176. class TasksExecution(BASE, models.TimestampMixin, models.ModelBase,
  177. models.SoftDeleteMixin):
  178. __tablename__ = 'tasks_execution'
  179. id = sqlalchemy.Column(sqlalchemy.String(36),
  180. default=lambda: str(uuid.uuid4()),
  181. primary_key=True)
  182. action_id = sqlalchemy.Column(
  183. sqlalchemy.String(36),
  184. sqlalchemy.ForeignKey('base_transfer_action.base_id'), nullable=False)
  185. # TODO(alexpilotti): Add soft delete filter
  186. tasks = orm.relationship(Task, cascade="all,delete",
  187. backref=orm.backref('execution'))
  188. status = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
  189. number = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
  190. type = sqlalchemy.Column(sqlalchemy.String(255))
  191. def to_dict(self):
  192. result = {
  193. "id": self.id,
  194. "action_id": self.action_id,
  195. "tasks": [],
  196. "status": self.status,
  197. "number": self.number,
  198. "type": self.type,
  199. "created_at": self.created_at,
  200. "updated_at": self.updated_at,
  201. "deleted_at": self.deleted_at,
  202. "deleted": self.deleted,
  203. }
  204. for tsk in self.tasks:
  205. result["tasks"].append(tsk.to_dict())
  206. return result
  207. class BaseTransferAction(BASE, models.TimestampMixin, models.ModelBase,
  208. models.SoftDeleteMixin):
  209. __tablename__ = 'base_transfer_action'
  210. base_id = sqlalchemy.Column(sqlalchemy.String(36),
  211. default=lambda: str(uuid.uuid4()),
  212. primary_key=True)
  213. user_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  214. project_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  215. destination_environment = sqlalchemy.Column(types.Json, nullable=True)
  216. type = sqlalchemy.Column(sqlalchemy.String(50))
  217. executions = orm.relationship(TasksExecution, cascade="all,delete",
  218. backref=orm.backref('action'),
  219. primaryjoin="and_(BaseTransferAction."
  220. "base_id==TasksExecution.action_id, "
  221. "TasksExecution.deleted=='0')")
  222. instances = sqlalchemy.Column(types.List, nullable=False)
  223. last_execution_status = sqlalchemy.Column(
  224. sqlalchemy.String(255), nullable=False,
  225. default=lambda: constants.EXECUTION_STATUS_UNEXECUTED)
  226. reservation_id = sqlalchemy.Column(sqlalchemy.String(36), nullable=True)
  227. info = orm.deferred(sqlalchemy.Column(types.Bson, nullable=False))
  228. notes = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
  229. origin_endpoint_id = sqlalchemy.Column(
  230. sqlalchemy.String(36),
  231. sqlalchemy.ForeignKey('endpoint.id'), nullable=False)
  232. destination_endpoint_id = sqlalchemy.Column(
  233. sqlalchemy.String(36),
  234. sqlalchemy.ForeignKey('endpoint.id'), nullable=False)
  235. transfer_result = sqlalchemy.Column(types.Json, nullable=True)
  236. network_map = sqlalchemy.Column(types.Json, nullable=True)
  237. storage_mappings = sqlalchemy.Column(types.Json, nullable=True)
  238. source_environment = sqlalchemy.Column(types.Json, nullable=True)
  239. origin_minion_pool_id = sqlalchemy.Column(
  240. sqlalchemy.String(36),
  241. sqlalchemy.ForeignKey('minion_pool.id'), nullable=True)
  242. destination_minion_pool_id = sqlalchemy.Column(
  243. sqlalchemy.String(36),
  244. sqlalchemy.ForeignKey('minion_pool.id'), nullable=True)
  245. instance_osmorphing_minion_pool_mappings = sqlalchemy.Column(
  246. types.Json, nullable=False, default=lambda: {})
  247. user_scripts = sqlalchemy.Column(types.Json, nullable=True)
  248. __mapper_args__ = {
  249. 'polymorphic_identity': 'base_transfer_action',
  250. 'polymorphic_on': type,
  251. }
  252. def to_dict(self, include_task_info=True, include_executions=True):
  253. result = {
  254. "base_id": self.base_id,
  255. "user_id": self.user_id,
  256. "project_id": self.project_id,
  257. "destination_environment": self.destination_environment,
  258. "type": self.type,
  259. "executions": [],
  260. "instances": self.instances,
  261. "reservation_id": self.reservation_id,
  262. "notes": self.notes,
  263. "origin_endpoint_id": self.origin_endpoint_id,
  264. "destination_endpoint_id": self.destination_endpoint_id,
  265. "transfer_result": self.transfer_result,
  266. "network_map": self.network_map,
  267. "storage_mappings": self.storage_mappings,
  268. "source_environment": self.source_environment,
  269. "last_execution_status": self.last_execution_status,
  270. "created_at": self.created_at,
  271. "updated_at": self.updated_at,
  272. "deleted_at": self.deleted_at,
  273. "deleted": self.deleted,
  274. "origin_minion_pool_id": self.origin_minion_pool_id,
  275. "destination_minion_pool_id": self.destination_minion_pool_id,
  276. "instance_osmorphing_minion_pool_mappings":
  277. self.instance_osmorphing_minion_pool_mappings,
  278. "user_scripts": self.user_scripts,
  279. }
  280. if include_executions:
  281. for ex in self.executions:
  282. result["executions"].append(ex.to_dict())
  283. if include_task_info:
  284. result["info"] = self.info
  285. return result
  286. class Transfer(BaseTransferAction):
  287. __tablename__ = 'transfer'
  288. id = sqlalchemy.Column(
  289. sqlalchemy.String(36),
  290. sqlalchemy.ForeignKey(
  291. 'base_transfer_action.base_id'), primary_key=True)
  292. scenario = sqlalchemy.Column(
  293. sqlalchemy.String(255), nullable=False,
  294. default=constants.TRANSFER_SCENARIO_REPLICA)
  295. __mapper_args__ = {
  296. 'polymorphic_identity': 'transfer',
  297. }
  298. def to_dict(self, include_task_info=True, include_executions=True):
  299. base = super(Transfer, self).to_dict(
  300. include_task_info=include_task_info,
  301. include_executions=include_executions)
  302. base.update({
  303. "id": self.id,
  304. "scenario": self.scenario})
  305. return base
  306. class Deployment(BaseTransferAction):
  307. __tablename__ = 'deployment'
  308. id = sqlalchemy.Column(
  309. sqlalchemy.String(36),
  310. sqlalchemy.ForeignKey(
  311. 'base_transfer_action.base_id'), primary_key=True)
  312. transfer_id = sqlalchemy.Column(
  313. sqlalchemy.String(36),
  314. sqlalchemy.ForeignKey('transfer.id'), nullable=False)
  315. transfer = orm.relationship(
  316. Transfer, backref=orm.backref("deployments"),
  317. foreign_keys=[transfer_id])
  318. __mapper_args__ = {
  319. 'polymorphic_identity': 'deployment',
  320. }
  321. def to_dict(self, include_task_info=True, include_tasks=True):
  322. base = super(Deployment, self).to_dict(
  323. include_task_info=include_task_info,
  324. include_executions=include_tasks)
  325. base.update({
  326. "id": self.id,
  327. "transfer_id": self.transfer_id,
  328. "transfer_scenario_type": self.transfer.scenario,
  329. })
  330. return base
  331. class ServiceRegionMapping(
  332. BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
  333. __tablename__ = "service_region_mapping"
  334. id = sqlalchemy.Column(
  335. sqlalchemy.String(36),
  336. default=lambda: str(uuid.uuid4()),
  337. nullable=False,
  338. primary_key=True)
  339. service_id = sqlalchemy.Column(
  340. sqlalchemy.String(36),
  341. sqlalchemy.ForeignKey('service.id'),
  342. nullable=False)
  343. region_id = sqlalchemy.Column(
  344. sqlalchemy.String(36),
  345. sqlalchemy.ForeignKey('region.id'),
  346. nullable=False)
  347. class Service(BASE, models.TimestampMixin, models.ModelBase,
  348. models.SoftDeleteMixin):
  349. __tablename__ = "service"
  350. __table_args__ = (
  351. schema.UniqueConstraint("host", "topic", "deleted",
  352. name="uniq_services0host0topic0deleted"),
  353. schema.UniqueConstraint("host", "binary", "deleted",
  354. name="uniq_services0host0binary0deleted"))
  355. id = sqlalchemy.Column(
  356. sqlalchemy.String(36), default=lambda: str(uuid.uuid4()),
  357. primary_key=True)
  358. host = sqlalchemy.Column(
  359. sqlalchemy.String(255), nullable=False)
  360. binary = sqlalchemy.Column(
  361. sqlalchemy.String(255), nullable=False)
  362. topic = sqlalchemy.Column(
  363. sqlalchemy.String(255), nullable=True, default=None)
  364. enabled = sqlalchemy.Column(
  365. sqlalchemy.Boolean, nullable=False, default=lambda: False)
  366. status = sqlalchemy.Column(
  367. sqlalchemy.String(255), nullable=False,
  368. default=lambda: constants.SERVICE_STATUS_UNKNOWN)
  369. providers = sqlalchemy.Column(types.Json(), nullable=True)
  370. specs = sqlalchemy.Column(types.Json(), nullable=True)
  371. mapped_regions = orm.relationship(
  372. 'Region', back_populates='mapped_services',
  373. secondary="service_region_mapping")
  374. class EndpointRegionMapping(
  375. BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
  376. __tablename__ = "endpoint_region_mapping"
  377. id = sqlalchemy.Column(
  378. sqlalchemy.String(36),
  379. default=lambda: str(uuid.uuid4()),
  380. nullable=False,
  381. primary_key=True)
  382. endpoint_id = sqlalchemy.Column(
  383. sqlalchemy.String(36),
  384. sqlalchemy.ForeignKey('endpoint.id'),
  385. nullable=False)
  386. region_id = sqlalchemy.Column(
  387. sqlalchemy.String(36),
  388. sqlalchemy.ForeignKey('region.id'),
  389. nullable=False)
  390. class Region(
  391. BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
  392. __tablename__ = "region"
  393. id = sqlalchemy.Column(
  394. sqlalchemy.String(36),
  395. default=lambda: str(uuid.uuid4()),
  396. nullable=False,
  397. primary_key=True)
  398. name = sqlalchemy.Column(
  399. sqlalchemy.String(255),
  400. nullable=False)
  401. description = sqlalchemy.Column(
  402. sqlalchemy.String(1024),
  403. nullable=True)
  404. enabled = sqlalchemy.Column(
  405. sqlalchemy.Boolean,
  406. default=lambda: False,
  407. nullable=False)
  408. mapped_endpoints = orm.relationship(
  409. 'Endpoint', back_populates='mapped_regions',
  410. secondary="endpoint_region_mapping")
  411. mapped_services = orm.relationship(
  412. 'Service', back_populates='mapped_regions',
  413. secondary="service_region_mapping")
  414. class MinionMachine(BASE, models.TimestampMixin, models.ModelBase,
  415. models.SoftDeleteMixin):
  416. __tablename__ = "minion_machine"
  417. id = sqlalchemy.Column(sqlalchemy.String(36),
  418. default=lambda: str(uuid.uuid4()),
  419. primary_key=True)
  420. user_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  421. project_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  422. pool_id = sqlalchemy.Column(
  423. sqlalchemy.String(36),
  424. sqlalchemy.ForeignKey('minion_pool.id'),
  425. nullable=False)
  426. allocation_status = sqlalchemy.Column(
  427. sqlalchemy.String(255), nullable=False,
  428. default=lambda: constants.MINION_MACHINE_STATUS_UNINITIALIZED)
  429. allocated_action = sqlalchemy.Column(
  430. sqlalchemy.String(36), nullable=True)
  431. power_status = sqlalchemy.Column(
  432. sqlalchemy.String(255), nullable=False)
  433. last_used_at = sqlalchemy.Column(
  434. sqlalchemy.types.DateTime, nullable=True)
  435. connection_info = sqlalchemy.Column(
  436. types.Json, nullable=True)
  437. backup_writer_connection_info = sqlalchemy.Column(
  438. types.Json, nullable=True)
  439. provider_properties = sqlalchemy.Column(
  440. types.Json, nullable=True)
  441. def to_dict(self):
  442. result = {
  443. "id": self.id,
  444. "user_id": self.user_id,
  445. "project_id": self.project_id,
  446. "created_at": self.created_at,
  447. "updated_at": self.updated_at,
  448. "deleted_at": self.deleted_at,
  449. "deleted": self.deleted,
  450. "pool_id": self.pool_id,
  451. "allocation_status": self.allocation_status,
  452. "power_status": self.power_status,
  453. "connection_info": self.connection_info,
  454. "allocated_action": self.allocated_action,
  455. "last_used_at": self.last_used_at,
  456. "backup_writer_connection_info": (
  457. self.backup_writer_connection_info),
  458. "provider_properties": self.provider_properties
  459. }
  460. return result
  461. class MinionPool(
  462. BASE, models.TimestampMixin, models.ModelBase,
  463. models.SoftDeleteMixin):
  464. __tablename__ = 'minion_pool'
  465. id = sqlalchemy.Column(
  466. sqlalchemy.String(36),
  467. primary_key=True)
  468. user_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  469. project_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  470. maintenance_trust_id = sqlalchemy.Column(
  471. sqlalchemy.String(255), nullable=True)
  472. name = sqlalchemy.Column(
  473. sqlalchemy.String(255),
  474. nullable=False)
  475. notes = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
  476. endpoint_id = sqlalchemy.Column(
  477. sqlalchemy.String(36),
  478. sqlalchemy.ForeignKey('endpoint.id'), nullable=False)
  479. os_type = sqlalchemy.Column(
  480. sqlalchemy.String(255), nullable=False)
  481. platform = sqlalchemy.Column(
  482. sqlalchemy.String(255), nullable=False)
  483. environment_options = sqlalchemy.Column(types.Json, nullable=True)
  484. status = sqlalchemy.Column(
  485. sqlalchemy.String(255), nullable=False,
  486. default=lambda: constants.MINION_POOL_STATUS_UNKNOWN)
  487. shared_resources = sqlalchemy.Column(
  488. types.Json, nullable=True)
  489. minimum_minions = sqlalchemy.Column(
  490. sqlalchemy.Integer, nullable=False)
  491. maximum_minions = sqlalchemy.Column(
  492. sqlalchemy.Integer, nullable=False)
  493. minion_max_idle_time = sqlalchemy.Column(
  494. sqlalchemy.Integer, nullable=False)
  495. minion_retention_strategy = sqlalchemy.Column(
  496. sqlalchemy.String(255), nullable=False)
  497. minion_machines = orm.relationship(
  498. MinionMachine, backref=orm.backref('minion_pool'),
  499. primaryjoin="and_(MinionMachine.pool_id==MinionPool.id, "
  500. "MinionMachine.deleted=='0')")
  501. events = orm.relationship(MinionPoolEvent, cascade="all,delete",
  502. backref=orm.backref('minion_pool'),
  503. order_by=MinionPoolEvent.index)
  504. progress_updates = orm.relationship(MinionPoolProgressUpdate,
  505. cascade="all,delete",
  506. backref=orm.backref('minion_pool'),
  507. order_by=(
  508. MinionPoolProgressUpdate.index))
  509. def to_dict(
  510. self, include_machines=True, include_events=True,
  511. include_progress_updates=True):
  512. base = {
  513. "id": self.id,
  514. "name": self.name,
  515. "notes": self.notes,
  516. "endpoint_id": self.endpoint_id,
  517. "environment_options": self.environment_options,
  518. "os_type": self.os_type,
  519. "maintenance_trust_id": self.maintenance_trust_id,
  520. "platform": self.platform,
  521. "created_at": self.created_at,
  522. "updated_at": self.updated_at,
  523. "deleted_at": self.deleted_at,
  524. "deleted": self.deleted,
  525. "shared_resources": self.shared_resources,
  526. "status": self.status,
  527. "minimum_minions": self.minimum_minions,
  528. "maximum_minions": self.maximum_minions,
  529. "minion_max_idle_time": self.minion_max_idle_time,
  530. "minion_retention_strategy": self.minion_retention_strategy}
  531. base["minion_machines"] = []
  532. if include_machines:
  533. base["minion_machines"] = [
  534. machine.to_dict() for machine in self.minion_machines]
  535. if include_events:
  536. base["events"] = [
  537. ev.to_dict() for ev in self.events]
  538. if include_progress_updates:
  539. base["progress_updates"] = [
  540. pu.to_dict() for pu in self.progress_updates]
  541. return base
  542. class Endpoint(BASE, models.TimestampMixin, models.ModelBase,
  543. models.SoftDeleteMixin):
  544. __tablename__ = 'endpoint'
  545. id = sqlalchemy.Column(sqlalchemy.String(36),
  546. default=lambda: str(uuid.uuid4()),
  547. primary_key=True)
  548. user_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  549. project_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  550. connection_info = sqlalchemy.Column(types.Json, nullable=False)
  551. type = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  552. name = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
  553. description = sqlalchemy.Column(sqlalchemy.String(1024), nullable=True)
  554. origin_actions = orm.relationship(
  555. BaseTransferAction, backref=orm.backref('origin_endpoint'),
  556. primaryjoin="and_(BaseTransferAction.origin_endpoint_id==Endpoint.id, "
  557. "BaseTransferAction.deleted=='0')")
  558. destination_actions = orm.relationship(
  559. BaseTransferAction, backref=orm.backref('destination_endpoint'),
  560. primaryjoin="and_(BaseTransferAction.destination_endpoint_id=="
  561. "Endpoint.id, BaseTransferAction.deleted=='0')")
  562. minion_pools = orm.relationship(
  563. MinionPool, backref=orm.backref('endpoint'),
  564. primaryjoin="and_(MinionPool.endpoint_id=="
  565. "Endpoint.id, MinionPool.deleted=='0')")
  566. mapped_regions = orm.relationship(
  567. 'Region', back_populates='mapped_endpoints',
  568. secondary="endpoint_region_mapping")
  569. class TransferSchedule(BASE, models.TimestampMixin, models.ModelBase,
  570. models.SoftDeleteMixin):
  571. __tablename__ = "transfer_schedules"
  572. id = sqlalchemy.Column(sqlalchemy.String(36),
  573. default=lambda: str(uuid.uuid4()),
  574. primary_key=True)
  575. transfer_id = sqlalchemy.Column(
  576. sqlalchemy.String(36),
  577. sqlalchemy.ForeignKey('transfer.id'), nullable=False)
  578. transfer = orm.relationship(
  579. Transfer, backref=orm.backref("schedules"), foreign_keys=[transfer_id])
  580. schedule = sqlalchemy.Column(types.Json, nullable=False)
  581. expiration_date = sqlalchemy.Column(
  582. sqlalchemy.types.DateTime, nullable=True)
  583. enabled = sqlalchemy.Column(
  584. sqlalchemy.Boolean, nullable=False, default=lambda: False)
  585. shutdown_instance = sqlalchemy.Column(
  586. sqlalchemy.Boolean, nullable=False, default=False)
  587. trust_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)