Skip to content

Commit efac7ad

Browse files
Enable resource "un-delete" process
1 parent 9c69c5c commit efac7ad

File tree

5 files changed

+45
-18
lines changed

5 files changed

+45
-18
lines changed

gnocchi/chef.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from gnocchi import carbonara
2323
from gnocchi import indexer
24+
from gnocchi import utils
2425

2526
LOG = daiquiri.getLogger(__name__)
2627

@@ -51,6 +52,7 @@ def __init__(self, coord, incoming, index, storage):
5152
self.index = index
5253
self.storage = storage
5354

55+
5456
def resource_ended_at_normalization(self, metric_inactive_after):
5557
"""Marks resources as ended at if needed.
5658
@@ -64,12 +66,9 @@ def resource_ended_at_normalization(self, metric_inactive_after):
6466
inactive, according to `metric_inactive_after` parameter. Therefore,
6567
we do not need to lock these metrics while processing, as they are
6668
inactive, and chances are that they will not receive measures anymore.
67-
We will not "undelete" the resource, if it starts receiving measures
68-
again. If there will ever be a case like this, we need to implement
69-
some workflow to handle it.
7069
"""
7170

72-
momment_now = datetime.datetime.utcnow()
71+
momment_now = utils.utcnow()
7372
momment = momment_now - datetime.timedelta(
7473
seconds=metric_inactive_after)
7574

@@ -91,6 +90,13 @@ def resource_ended_at_normalization(self, metric_inactive_after):
9190
metrics_by_resource_id[resource_id].append(metric)
9291

9392
for resource_id in metrics_by_resource_id.keys():
93+
if resource_id is None:
94+
LOG.debug("We do not need to process inactive metrics that do "
95+
"not have resource. Therefore, these metrics [%s] "
96+
"will be considered inactive, but there is nothing "
97+
"else we can do in this process.",
98+
metrics_by_resource_id[resource_id])
99+
continue
94100
resource = self.index.get_resource(
95101
"generic", resource_id, with_metrics=True)
96102
resource_metrics = resource.metrics
@@ -101,13 +107,15 @@ def resource_ended_at_normalization(self, metric_inactive_after):
101107
if m not in resource_inactive_metrics:
102108
all_metrics_are_inactive = False
103109
LOG.debug("Not all metrics of resource [%s] are inactive. "
104-
"Metric [%s] is not inactive.", resource, m)
110+
"Metric [%s] is not inactive. The inactive "
111+
"metrics are [%s].",
112+
resource, m, resource_inactive_metrics)
105113
break
106114

107115
if all_metrics_are_inactive:
108116
LOG.info("All metrics [%s] of resource [%s] are inactive."
109117
"Therefore, we will mark it as finished with an"
110-
"ended at timestmap.")
118+
"ended at timestmap.", resource_metrics, resource)
111119
if resource.ended_at is not None:
112120
LOG.debug(
113121
"Resource [%s] already has an ended at value.", resource)

gnocchi/cli/metricd.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ def _run_job(self):
278278
LOG.debug("Finished the cleaning of raw data points for metrics that "
279279
"are no longer receiving measures.")
280280

281-
if self.conf.metricd.metric_inactive_after:
281+
if (self.conf.metricd.metric_inactive_after and
282+
self.conf.metricd.metric_inactive_after > 0):
282283
LOG.debug("Starting resource ended at field normalization.")
283284
self.chef.resource_ended_at_normalization(
284285
self.conf.metricd.metric_inactive_after)

gnocchi/indexer/alembic/versions/f89ed2e3c2ec_create_last_measure_timestamp_column.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,17 @@
1414
#
1515

1616
"""Create last measure push timestamp column
17-
1817
Revision ID: f89ed2e3c2ec
1918
Revises: 18fff4509e3e
2019
Create Date: 2024-04-24 09:16:00
21-
2220
"""
2321

2422
from alembic import op
2523

26-
import datetime
2724
import sqlalchemy
2825

26+
from sqlalchemy.sql import func
27+
2928
# revision identifiers, used by Alembic.
3029
revision = 'f89ed2e3c2ec'
3130
down_revision = '18fff4509e3e'
@@ -37,4 +36,4 @@ def upgrade():
3736
op.add_column(
3837
"metric", sqlalchemy.Column(
3938
"last_measure_timestamp", sqlalchemy.DateTime,
40-
nullable=True, default=datetime.datetime.utcnow()))
39+
nullable=False, server_default=func.current_timestamp()))

gnocchi/indexer/sqlalchemy_base.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
import sqlalchemy
2121
from sqlalchemy.ext import declarative
2222
from sqlalchemy.orm import declarative_base
23+
from sqlalchemy.sql import func
2324

2425
import sqlalchemy_utils
2526

2627
from gnocchi import archive_policy
2728
from gnocchi import indexer
28-
from gnocchi.indexer import sqlalchemy_types as types
2929
from gnocchi import resource_type
3030
from gnocchi import utils
3131

@@ -120,7 +120,7 @@ class Metric(Base, GnocchiBase, indexer.Metric):
120120
# chances are that the resource ceased existing in the backend.
121121
last_measure_timestamp = sqlalchemy.Column(
122122
"last_measure_timestamp", sqlalchemy.DateTime,
123-
nullable=True, default=datetime.datetime.utcnow())
123+
nullable=False, server_default=func.current_timestamp())
124124

125125
def jsonify(self):
126126
d = {
@@ -199,7 +199,7 @@ class ResourceType(Base, GnocchiBase, resource_type.ResourceType):
199199
name="resource_type_state_enum"),
200200
nullable=False,
201201
server_default="creating")
202-
updated_at = sqlalchemy.Column(types.TimestampUTC, nullable=False,
202+
updated_at = sqlalchemy.Column(indexer.types.TimestampUTC, nullable=False,
203203
# NOTE(jd): We would like to use
204204
# sqlalchemy.func.now, but we can't
205205
# because the type of PreciseTimestamp in
@@ -263,11 +263,12 @@ def type(cls):
263263
nullable=False)
264264

265265
creator = sqlalchemy.Column(sqlalchemy.String(255))
266-
started_at = sqlalchemy.Column(types.TimestampUTC, nullable=False,
266+
started_at = sqlalchemy.Column(indexer.types.TimestampUTC, nullable=False,
267267
default=lambda: utils.utcnow())
268-
revision_start = sqlalchemy.Column(types.TimestampUTC, nullable=False,
268+
revision_start = sqlalchemy.Column(indexer.types.TimestampUTC,
269+
nullable=False,
269270
default=lambda: utils.utcnow())
270-
ended_at = sqlalchemy.Column(types.TimestampUTC)
271+
ended_at = sqlalchemy.Column(indexer.types.TimestampUTC)
271272
user_id = sqlalchemy.Column(sqlalchemy.String(255))
272273
project_id = sqlalchemy.Column(sqlalchemy.String(255))
273274
original_resource_id = sqlalchemy.Column(sqlalchemy.String(255),
@@ -307,7 +308,8 @@ class ResourceHistory(ResourceMixin, Base, GnocchiBase):
307308
ondelete="CASCADE",
308309
name="fk_rh_id_resource_id"),
309310
nullable=False)
310-
revision_end = sqlalchemy.Column(types.TimestampUTC, nullable=False,
311+
revision_end = sqlalchemy.Column(indexer.types.TimestampUTC,
312+
nullable=False,
311313
default=lambda: utils.utcnow())
312314
metrics = sqlalchemy.orm.relationship(
313315
Metric, primaryjoin="Metric.resource_id == ResourceHistory.id",

gnocchi/storage/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,23 @@ def _map_compute_splits_operations(bound_timeserie):
691691
# Mark when the metric receives its latest measures
692692
indexer_driver.update_last_measure_timestmap(metric.id)
693693

694+
resource_id = metric.resource_id
695+
if resource_id:
696+
resource = indexer_driver.get_resource('generic', resource_id)
697+
LOG.debug("Checking if resource [%s] of metric [%s] with "
698+
"resource ID [%s] needs to be 'undeleted.'",
699+
resource, metric.id, resource_id)
700+
if resource.ended_at is not None:
701+
LOG.info("Resource [%s] was marked with a timestamp for the "
702+
"'ended_at' field. However, it received a "
703+
"measurement for metric [%s]. Therefore, we undelete "
704+
"it.", resource, metric)
705+
indexer_driver.update_resource(
706+
"generic", resource_id, ended_at=None)
707+
else:
708+
LOG.debug("Metric [%s] does not have a resource "
709+
"assigned to it.", metric)
710+
694711
with self.statistics.time("splits delete"):
695712
self._delete_metric_splits(splits_to_delete)
696713
self.statistics["splits delete"] += len(splits_to_delete)

0 commit comments

Comments
 (0)