# Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You 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. """ ARIA modeling service changes module """ # pylint: disable=no-self-argument, no-member, abstract-method from collections import namedtuple from sqlalchemy import ( Column, Text, DateTime, Enum, ) from sqlalchemy.ext.declarative import declared_attr from .types import (List, Dict) from .mixins import ModelMixin from . import relationship class ServiceUpdateBase(ModelMixin): """ Deployment update model representation. """ __tablename__ = 'service_update' __private_fields__ = ('service_fk', 'execution_fk') created_at = Column(DateTime, nullable=False, index=True) service_plan = Column(Dict, nullable=False) service_update_nodes = Column(Dict) service_update_service = Column(Dict) service_update_node_templates = Column(List) modified_entity_ids = Column(Dict) state = Column(Text) # region association proxies @declared_attr def execution_name(cls): return relationship.association_proxy('execution', cls.name_column_name()) @declared_attr def service_name(cls): return relationship.association_proxy('service', cls.name_column_name()) # endregion # region one_to_one relationships # endregion # region one_to_many relationships @declared_attr def steps(cls): return relationship.one_to_many(cls, 'service_update_step') # endregion # region many_to_one relationships @declared_attr def execution(cls): return relationship.one_to_one(cls, 'execution', back_populates=relationship.NO_BACK_POP) @declared_attr def service(cls): return relationship.many_to_one(cls, 'service', back_populates='updates') # endregion # region foreign keys @declared_attr def execution_fk(cls): return relationship.foreign_key('execution', nullable=True) @declared_attr def service_fk(cls): return relationship.foreign_key('service') # endregion def to_dict(self, suppress_error=False, **kwargs): dep_update_dict = super(ServiceUpdateBase, self).to_dict(suppress_error) #pylint: disable=no-member # Taking care of the fact the DeploymentSteps are _BaseModels dep_update_dict['steps'] = [step.to_dict() for step in self.steps] return dep_update_dict class ServiceUpdateStepBase(ModelMixin): """ Deployment update step model representation. """ __tablename__ = 'service_update_step' __private_fields__ = ('service_update_fk',) _action_types = namedtuple('ACTION_TYPES', 'ADD, REMOVE, MODIFY') ACTION_TYPES = _action_types(ADD='add', REMOVE='remove', MODIFY='modify') _entity_types = namedtuple( 'ENTITY_TYPES', 'NODE, RELATIONSHIP, PROPERTY, OPERATION, WORKFLOW, OUTPUT, DESCRIPTION, GROUP, PLUGIN') ENTITY_TYPES = _entity_types( NODE='node', RELATIONSHIP='relationship', PROPERTY='property', OPERATION='operation', WORKFLOW='workflow', OUTPUT='output', DESCRIPTION='description', GROUP='group', PLUGIN='plugin' ) action = Column(Enum(*ACTION_TYPES, name='action_type'), nullable=False) entity_id = Column(Text, nullable=False) entity_type = Column(Enum(*ENTITY_TYPES, name='entity_type'), nullable=False) # region association proxies @declared_attr def service_update_name(cls): return relationship.association_proxy('service_update', cls.name_column_name()) # endregion # region one_to_one relationships # endregion # region one_to_many relationships # endregion # region many_to_one relationships @declared_attr def service_update(cls): return relationship.many_to_one(cls, 'service_update', back_populates='steps') # endregion # region foreign keys @declared_attr def service_update_fk(cls): return relationship.foreign_key('service_update') # endregion def __hash__(self): return hash((getattr(self, self.id_column_name()), self.entity_id)) def __lt__(self, other): """ the order is 'remove' < 'modify' < 'add' :param other: :return: """ if not isinstance(other, self.__class__): return not self >= other if self.action != other.action: if self.action == 'remove': return_value = True elif self.action == 'add': return_value = False else: return_value = other.action == 'add' return return_value if self.action == 'add': return self.entity_type == 'node' and other.entity_type == 'relationship' if self.action == 'remove': return self.entity_type == 'relationship' and other.entity_type == 'node' return False class ServiceModificationBase(ModelMixin): """ Deployment modification model representation. """ __tablename__ = 'service_modification' __private_fields__ = ('service_fk',) STARTED = 'started' FINISHED = 'finished' ROLLEDBACK = 'rolledback' STATES = [STARTED, FINISHED, ROLLEDBACK] END_STATES = [FINISHED, ROLLEDBACK] context = Column(Dict) created_at = Column(DateTime, nullable=False, index=True) ended_at = Column(DateTime, index=True) modified_node_templates = Column(Dict) nodes = Column(Dict) status = Column(Enum(*STATES, name='service_modification_status')) # region association proxies @declared_attr def service_name(cls): return relationship.association_proxy('service', cls.name_column_name()) # endregion # region one_to_one relationships # endregion # region one_to_many relationships # endregion # region many_to_one relationships @declared_attr def service(cls): return relationship.many_to_one(cls, 'service', back_populates='modifications') # endregion # region foreign keys @declared_attr def service_fk(cls): return relationship.foreign_key('service') # endregion