|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
# Copyright 2010 - 2017 RhodeCode GmbH and the AppEnlight project authors
|
|
|
#
|
|
|
# Licensed 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.
|
|
|
|
|
|
from pyramid.view import view_config
|
|
|
from appenlight.models import DBSession, Datastores
|
|
|
from appenlight.forms import get_partition_deletion_form
|
|
|
|
|
|
import logging
|
|
|
|
|
|
from zope.sqlalchemy import mark_changed
|
|
|
from datetime import datetime
|
|
|
import sqlalchemy as sa
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
def get_partition_stats():
|
|
|
table_query = """
|
|
|
SELECT table_name
|
|
|
FROM information_schema.tables
|
|
|
GROUP BY table_name
|
|
|
ORDER BY table_name
|
|
|
"""
|
|
|
|
|
|
permanent_partitions = {}
|
|
|
daily_partitions = {}
|
|
|
|
|
|
def is_int(data):
|
|
|
try:
|
|
|
int(data)
|
|
|
return True
|
|
|
except Exception:
|
|
|
pass
|
|
|
return False
|
|
|
|
|
|
def add_key(key, holder):
|
|
|
if not ix_time in holder:
|
|
|
holder[ix_time] = {"pg": [], "elasticsearch": []}
|
|
|
|
|
|
for partition in list(Datastores.es.indices.get_alias("rcae*")):
|
|
|
if not partition.startswith("rcae"):
|
|
|
continue
|
|
|
split_data = partition.split("_")
|
|
|
permanent = False
|
|
|
# if we dont have a day then treat it as permanent partion
|
|
|
if False in list(map(is_int, split_data[-3:])):
|
|
|
ix_time = datetime(
|
|
|
year=int(split_data[-2]), month=int(split_data[-1]), day=1
|
|
|
).date()
|
|
|
permanent = True
|
|
|
else:
|
|
|
ix_time = datetime(
|
|
|
year=int(split_data[-3]),
|
|
|
month=int(split_data[-2]),
|
|
|
day=int(split_data[-1]),
|
|
|
).date()
|
|
|
|
|
|
ix_time = str(ix_time)
|
|
|
if permanent:
|
|
|
add_key(ix_time, permanent_partitions)
|
|
|
if ix_time not in permanent_partitions:
|
|
|
permanent_partitions[ix_time]["elasticsearch"] = []
|
|
|
permanent_partitions[ix_time]["elasticsearch"].append(partition)
|
|
|
else:
|
|
|
add_key(ix_time, daily_partitions)
|
|
|
if ix_time not in daily_partitions:
|
|
|
daily_partitions[ix_time]["elasticsearch"] = []
|
|
|
daily_partitions[ix_time]["elasticsearch"].append(partition)
|
|
|
|
|
|
for row in DBSession.execute(table_query):
|
|
|
splitted = row["table_name"].split("_")
|
|
|
if "p" in splitted:
|
|
|
# dealing with partition
|
|
|
split_data = [int(x) for x in splitted[splitted.index("p") + 1 :]]
|
|
|
if len(split_data) == 3:
|
|
|
ix_time = datetime(split_data[0], split_data[1], split_data[2]).date()
|
|
|
ix_time = str(ix_time)
|
|
|
add_key(ix_time, daily_partitions)
|
|
|
daily_partitions[ix_time]["pg"].append(row["table_name"])
|
|
|
else:
|
|
|
ix_time = datetime(split_data[0], split_data[1], 1).date()
|
|
|
ix_time = str(ix_time)
|
|
|
add_key(ix_time, permanent_partitions)
|
|
|
permanent_partitions[ix_time]["pg"].append(row["table_name"])
|
|
|
|
|
|
return permanent_partitions, daily_partitions
|
|
|
|
|
|
|
|
|
@view_config(
|
|
|
route_name="section_view",
|
|
|
permission="root_administration",
|
|
|
match_param=["section=admin_section", "view=partitions"],
|
|
|
renderer="json",
|
|
|
request_method="GET",
|
|
|
)
|
|
|
def index(request):
|
|
|
permanent_partitions, daily_partitions = get_partition_stats()
|
|
|
|
|
|
return {
|
|
|
"permanent_partitions": sorted(
|
|
|
list(permanent_partitions.items()), key=lambda x: x[0], reverse=True
|
|
|
),
|
|
|
"daily_partitions": sorted(
|
|
|
list(daily_partitions.items()), key=lambda x: x[0], reverse=True
|
|
|
),
|
|
|
}
|
|
|
|
|
|
|
|
|
@view_config(
|
|
|
route_name="section_view",
|
|
|
request_method="POST",
|
|
|
match_param=["section=admin_section", "view=partitions_remove"],
|
|
|
renderer="json",
|
|
|
permission="root_administration",
|
|
|
)
|
|
|
def partitions_remove(request):
|
|
|
permanent_partitions, daily_partitions = get_partition_stats()
|
|
|
pg_partitions = []
|
|
|
es_partitions = []
|
|
|
for item in list(permanent_partitions.values()) + list(daily_partitions.values()):
|
|
|
es_partitions.extend(item["elasticsearch"])
|
|
|
pg_partitions.extend(item["pg"])
|
|
|
FormCls = get_partition_deletion_form(es_partitions, pg_partitions)
|
|
|
form = FormCls(
|
|
|
es_index=request.unsafe_json_body["es_indices"],
|
|
|
pg_index=request.unsafe_json_body["pg_indices"],
|
|
|
confirm=request.unsafe_json_body["confirm"],
|
|
|
csrf_context=request,
|
|
|
)
|
|
|
if form.validate():
|
|
|
for ix in form.data["es_index"]:
|
|
|
log.warning("deleting ES partition: {}".format(ix))
|
|
|
Datastores.es.indices.delete(ix)
|
|
|
for ix in form.data["pg_index"]:
|
|
|
log.warning("deleting PG partition: {}".format(ix))
|
|
|
stmt = sa.text("DROP TABLE %s CASCADE" % sa.text(ix))
|
|
|
session = DBSession()
|
|
|
session.connection().execute(stmt)
|
|
|
mark_changed(session)
|
|
|
|
|
|
for field, error in form.errors.items():
|
|
|
msg = "%s: %s" % (field, error[0])
|
|
|
request.session.flash(msg, "error")
|
|
|
|
|
|
permanent_partitions, daily_partitions = get_partition_stats()
|
|
|
return {
|
|
|
"permanent_partitions": sorted(
|
|
|
list(permanent_partitions.items()), key=lambda x: x[0], reverse=True
|
|
|
),
|
|
|
"daily_partitions": sorted(
|
|
|
list(daily_partitions.items()), key=lambda x: x[0], reverse=True
|
|
|
),
|
|
|
}
|
|
|
|