Coverage for watcher/db/sqlalchemy/models.py: 98%
166 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-17 12:22 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-17 12:22 +0000
1# Copyright 2013 Hewlett-Packard Development Company, L.P.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
15"""
16SQLAlchemy models for watcher service
17"""
19from oslo_db.sqlalchemy import models
20from oslo_serialization import jsonutils
21from sqlalchemy import Boolean
22from sqlalchemy import Column
23from sqlalchemy import DateTime
24from sqlalchemy.ext.declarative import declarative_base
25from sqlalchemy import Float
26from sqlalchemy import ForeignKey
27from sqlalchemy import Integer
28from sqlalchemy import LargeBinary
29from sqlalchemy import Numeric
30from sqlalchemy import orm
31from sqlalchemy import String
32from sqlalchemy import Text
33from sqlalchemy.types import TypeDecorator, TEXT
34from sqlalchemy import UniqueConstraint
35import urllib.parse as urlparse
36from watcher import conf
38CONF = conf.CONF
41def table_args():
42 engine_name = urlparse.urlparse(CONF.database.connection).scheme
43 if engine_name == 'mysql': 43 ↛ 44line 43 didn't jump to line 44 because the condition on line 43 was never true
44 return {'mysql_engine': CONF.database.mysql_engine,
45 'mysql_charset': "utf8"}
46 return None
49class JsonEncodedType(TypeDecorator):
50 """Abstract base type serialized as json-encoded string in db."""
52 type = None
53 impl = TEXT
55 def process_bind_param(self, value, dialect):
56 if value is None:
57 # Save default value according to current type to keep the
58 # interface the consistent.
59 value = self.type()
60 elif not isinstance(value, self.type): 60 ↛ 61line 60 didn't jump to line 61 because the condition on line 60 was never true
61 raise TypeError("%s supposes to store %s objects, but %s given"
62 % (self.__class__.__name__,
63 self.type.__name__,
64 type(value).__name__))
65 serialized_value = jsonutils.dumps(value)
66 return serialized_value
68 def process_result_value(self, value, dialect):
69 if value is not None:
70 value = jsonutils.loads(value)
71 return value
74class JSONEncodedDict(JsonEncodedType):
75 """Represents dict serialized as json-encoded string in db."""
77 type = dict
80class JSONEncodedList(JsonEncodedType):
81 """Represents list serialized as json-encoded string in db."""
83 type = list
86class WatcherBase(models.SoftDeleteMixin,
87 models.TimestampMixin, models.ModelBase):
88 metadata = None
90 def as_dict(self):
91 d = {}
92 for c in self.__table__.columns:
93 d[c.name] = self[c.name]
94 return d
97Base = declarative_base(cls=WatcherBase)
100class Goal(Base):
101 """Represents a goal."""
103 __tablename__ = 'goals'
104 __table_args__ = (
105 UniqueConstraint('uuid', name='uniq_goals0uuid'),
106 UniqueConstraint('name', 'deleted', name='uniq_goals0name'),
107 table_args(),
108 )
109 id = Column(Integer, primary_key=True, autoincrement=True)
110 uuid = Column(String(36))
111 name = Column(String(63), nullable=False)
112 display_name = Column(String(63), nullable=False)
113 efficacy_specification = Column(JSONEncodedList, nullable=False)
116class Strategy(Base):
117 """Represents a strategy."""
119 __tablename__ = 'strategies'
120 __table_args__ = (
121 UniqueConstraint('uuid', name='uniq_strategies0uuid'),
122 UniqueConstraint('name', 'deleted', name='uniq_strategies0name'),
123 table_args()
124 )
125 id = Column(Integer, primary_key=True, autoincrement=True)
126 uuid = Column(String(36))
127 name = Column(String(63), nullable=False)
128 display_name = Column(String(63), nullable=False)
129 goal_id = Column(Integer, ForeignKey('goals.id'), nullable=False)
130 parameters_spec = Column(JSONEncodedDict, nullable=True)
132 goal = orm.relationship(Goal, foreign_keys=goal_id, lazy=None)
135class AuditTemplate(Base):
136 """Represents an audit template."""
138 __tablename__ = 'audit_templates'
139 __table_args__ = (
140 UniqueConstraint('uuid', name='uniq_audit_templates0uuid'),
141 UniqueConstraint('name', 'deleted', name='uniq_audit_templates0name'),
142 table_args()
143 )
144 id = Column(Integer, primary_key=True)
145 uuid = Column(String(36))
146 name = Column(String(63), nullable=True)
147 description = Column(String(255), nullable=True)
148 goal_id = Column(Integer, ForeignKey('goals.id'), nullable=False)
149 strategy_id = Column(Integer, ForeignKey('strategies.id'), nullable=True)
150 scope = Column(JSONEncodedList)
152 goal = orm.relationship(Goal, foreign_keys=goal_id, lazy=None)
153 strategy = orm.relationship(Strategy, foreign_keys=strategy_id, lazy=None)
156class Audit(Base):
157 """Represents an audit."""
159 __tablename__ = 'audits'
160 __table_args__ = (
161 UniqueConstraint('uuid', name='uniq_audits0uuid'),
162 UniqueConstraint('name', 'deleted', name='uniq_audits0name'),
163 table_args()
164 )
165 id = Column(Integer, primary_key=True, autoincrement=True)
166 uuid = Column(String(36))
167 name = Column(String(63), nullable=True)
168 audit_type = Column(String(20))
169 state = Column(String(20), nullable=True)
170 parameters = Column(JSONEncodedDict, nullable=True)
171 interval = Column(String(36), nullable=True)
172 goal_id = Column(Integer, ForeignKey('goals.id'), nullable=False)
173 strategy_id = Column(Integer, ForeignKey('strategies.id'), nullable=True)
174 scope = Column(JSONEncodedList, nullable=True)
175 auto_trigger = Column(Boolean, nullable=False)
176 next_run_time = Column(DateTime, nullable=True)
177 hostname = Column(String(255), nullable=True)
178 start_time = Column(DateTime, nullable=True)
179 end_time = Column(DateTime, nullable=True)
180 force = Column(Boolean, nullable=False)
182 goal = orm.relationship(Goal, foreign_keys=goal_id, lazy=None)
183 strategy = orm.relationship(Strategy, foreign_keys=strategy_id, lazy=None)
186class ActionPlan(Base):
187 """Represents an action plan."""
189 __tablename__ = 'action_plans'
190 __table_args__ = (
191 UniqueConstraint('uuid', name='uniq_action_plans0uuid'),
192 table_args()
193 )
194 id = Column(Integer, primary_key=True, autoincrement=True)
195 uuid = Column(String(36))
196 audit_id = Column(Integer, ForeignKey('audits.id'), nullable=False)
197 strategy_id = Column(Integer, ForeignKey('strategies.id'), nullable=False)
198 state = Column(String(20), nullable=True)
199 global_efficacy = Column(JSONEncodedList, nullable=True)
200 hostname = Column(String(255), nullable=True)
202 audit = orm.relationship(Audit, foreign_keys=audit_id, lazy=None)
203 strategy = orm.relationship(Strategy, foreign_keys=strategy_id, lazy=None)
206class Action(Base):
207 """Represents an action."""
209 __tablename__ = 'actions'
210 __table_args__ = (
211 UniqueConstraint('uuid', name='uniq_actions0uuid'),
212 table_args()
213 )
214 id = Column(Integer, primary_key=True, autoincrement=True)
215 uuid = Column(String(36), nullable=False)
216 action_plan_id = Column(Integer, ForeignKey('action_plans.id'),
217 nullable=False)
218 # only for the first version
219 action_type = Column(String(255), nullable=False)
220 input_parameters = Column(JSONEncodedDict, nullable=True)
221 state = Column(String(20), nullable=True)
222 parents = Column(JSONEncodedList, nullable=True)
224 action_plan = orm.relationship(
225 ActionPlan, foreign_keys=action_plan_id, lazy=None)
228class EfficacyIndicator(Base):
229 """Represents an efficacy indicator."""
231 __tablename__ = 'efficacy_indicators'
232 __table_args__ = (
233 UniqueConstraint('uuid', name='uniq_efficacy_indicators0uuid'),
234 table_args()
235 )
236 id = Column(Integer, primary_key=True, autoincrement=True)
237 uuid = Column(String(36))
238 name = Column(String(63))
239 description = Column(String(255), nullable=True)
240 unit = Column(String(63), nullable=True)
241 # this column is deprecated due to bug
242 # https://bugs.launchpad.net/watcher/+bug/2103458
243 value = Column(Numeric())
244 data = Column(Float())
245 action_plan_id = Column(Integer, ForeignKey('action_plans.id'),
246 nullable=False)
248 action_plan = orm.relationship(
249 ActionPlan, foreign_keys=action_plan_id, lazy=None)
252class ScoringEngine(Base):
253 """Represents a scoring engine."""
255 __tablename__ = 'scoring_engines'
256 __table_args__ = (
257 UniqueConstraint('uuid', name='uniq_scoring_engines0uuid'),
258 UniqueConstraint('name', 'deleted', name='uniq_scoring_engines0name'),
259 table_args()
260 )
261 id = Column(Integer, primary_key=True, autoincrement=True)
262 uuid = Column(String(36), nullable=False)
263 name = Column(String(63), nullable=False)
264 description = Column(String(255), nullable=True)
265 # Metainfo might contain some additional information about the data model.
266 # The format might vary between different models (e.g. be JSON, XML or
267 # even some custom format), the blob type should cover all scenarios.
268 metainfo = Column(Text, nullable=True)
271class Service(Base):
272 """Represents a service entity"""
274 __tablename__ = 'services'
275 __table_args__ = (
276 UniqueConstraint('host', 'name', 'deleted',
277 name="uniq_services0host0name0deleted"),
278 table_args()
279 )
280 id = Column(Integer, primary_key=True)
281 name = Column(String(255), nullable=False)
282 host = Column(String(255), nullable=False)
283 last_seen_up = Column(DateTime, nullable=True)
286class ActionDescription(Base):
287 """Represents a action description"""
289 __tablename__ = 'action_descriptions'
290 __table_args__ = (
291 UniqueConstraint('action_type',
292 name="uniq_action_description0action_type"),
293 table_args()
294 )
295 id = Column(Integer, primary_key=True)
296 action_type = Column(String(255), nullable=False)
297 description = Column(String(255), nullable=False)
300class APScheulerJob(Base):
301 """Represents apscheduler jobs"""
303 __tablename__ = 'apscheduler_jobs'
304 __table_args__ = (
305 UniqueConstraint('id',
306 name="uniq_apscheduler_jobs0id"),
307 table_args()
308 )
309 id = Column(String(191), nullable=False, primary_key=True)
310 next_run_time = Column(Float(25), index=True)
311 job_state = Column(LargeBinary, nullable=False)
312 tag = Column(JSONEncodedDict(), nullable=True)
313 service_id = Column(Integer, ForeignKey('services.id'),
314 nullable=False)
316 service = orm.relationship(
317 Service, foreign_keys=service_id, lazy=None)