feat: use custom type to handle existing naive datetimes
This commit is contained in:
parent
e22abb383c
commit
39bdac1ecf
45 changed files with 210 additions and 84 deletions
|
@ -3,24 +3,23 @@ import sys
|
||||||
from typing import Iterator
|
from typing import Iterator
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from flask import Flask, redirect, url_for, send_from_directory
|
from flask import Flask, redirect, send_from_directory, url_for
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from prometheus_client import make_wsgi_app, Metric, CollectorRegistry
|
from prometheus_client import CollectorRegistry, Metric, make_wsgi_app
|
||||||
from prometheus_client.metrics_core import GaugeMetricFamily, CounterMetricFamily
|
from prometheus_client.metrics_core import (CounterMetricFamily,
|
||||||
from prometheus_client.registry import Collector, REGISTRY
|
GaugeMetricFamily)
|
||||||
|
from prometheus_client.registry import REGISTRY, Collector
|
||||||
|
from prometheus_flask_exporter import PrometheusMetrics
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
from werkzeug.middleware.dispatcher import DispatcherMiddleware
|
||||||
|
|
||||||
from app.api import api
|
from app.api import api
|
||||||
from app.extensions import bootstrap
|
from app.extensions import bootstrap, db, migrate
|
||||||
from app.extensions import db
|
|
||||||
from app.extensions import migrate
|
|
||||||
from app.models.automation import Automation, AutomationState
|
from app.models.automation import Automation, AutomationState
|
||||||
from app.portal import portal
|
from app.portal import portal
|
||||||
from app.portal.report import report
|
from app.portal.report import report
|
||||||
from app.tfstate import tfstate
|
from app.tfstate import tfstate
|
||||||
from prometheus_flask_exporter import PrometheusMetrics
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_file("../config.yaml", load=yaml.safe_load)
|
app.config.from_file("../config.yaml", load=yaml.safe_load)
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import List, TypedDict, NotRequired, Optional
|
from typing import List, NotRequired, Optional, TypedDict
|
||||||
|
|
||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
from flask import request, abort, jsonify, Blueprint
|
from flask import Blueprint, abort, jsonify, request
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from sqlalchemy import exc
|
from sqlalchemy import exc
|
||||||
|
|
||||||
|
from app.api.util import (DOMAIN_NAME_REGEX, MAX_ALLOWED_ITEMS,
|
||||||
|
MAX_DOMAIN_NAME_LENGTH, ListFilter,
|
||||||
|
get_single_resource, list_resources,
|
||||||
|
validate_description)
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.api.util import ListFilter, MAX_DOMAIN_NAME_LENGTH, DOMAIN_NAME_REGEX, list_resources, MAX_ALLOWED_ITEMS, \
|
|
||||||
validate_description, get_single_resource
|
|
||||||
from app.models.base import Group
|
from app.models.base import Group
|
||||||
from app.models.onions import Onion
|
from app.models.onions import Onion
|
||||||
from app.util.onion import onion_hostname, decode_onion_keys
|
from app.util.onion import decode_onion_keys, onion_hostname
|
||||||
from app.util.x509 import validate_tls_keys
|
from app.util.x509 import validate_tls_keys
|
||||||
|
|
||||||
api_onion = Blueprint('api_onion', __name__)
|
api_onion = Blueprint('api_onion', __name__)
|
||||||
|
|
|
@ -2,9 +2,9 @@ import base64
|
||||||
import binascii
|
import binascii
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from typing import Union, Any, Literal, Type, Callable, Dict, List, Optional
|
from typing import Any, Callable, Dict, List, Literal, Optional, Type, Union
|
||||||
|
|
||||||
from flask import abort, request, jsonify
|
from flask import abort, jsonify, request
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from sqlalchemy import BinaryExpression, ColumnElement, select
|
from sqlalchemy import BinaryExpression, ColumnElement, select
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from flask import Blueprint, request, abort
|
from flask import Blueprint, abort, request
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
|
|
||||||
from app.api.util import ListFilter, MAX_DOMAIN_NAME_LENGTH, DOMAIN_NAME_REGEX, list_resources, MAX_ALLOWED_ITEMS
|
from app.api.util import (DOMAIN_NAME_REGEX, MAX_ALLOWED_ITEMS,
|
||||||
|
MAX_DOMAIN_NAME_LENGTH, ListFilter, list_resources)
|
||||||
from app.models.base import Group
|
from app.models.base import Group
|
||||||
from app.models.mirrors import Origin, Proxy
|
from app.models.mirrors import Origin, Proxy
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ Bypass Censorship Resource Names.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
|
|
@ -9,15 +9,15 @@ from typing import Any, Callable, Dict, List, Type
|
||||||
from sqlalchemy import inspect
|
from sqlalchemy import inspect
|
||||||
|
|
||||||
from app import app
|
from app import app
|
||||||
from app.cli import _SubparserType, BaseCliHandler
|
from app.cli import BaseCliHandler, _SubparserType
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.activity import Webhook, Activity
|
from app.models.activity import Activity, Webhook
|
||||||
from app.models.automation import AutomationLogs, Automation, AutomationState
|
from app.models.alarms import Alarm, AlarmState
|
||||||
from app.models.base import Group, MirrorList, PoolGroup, Pool
|
from app.models.automation import Automation, AutomationLogs, AutomationState
|
||||||
|
from app.models.base import Group, MirrorList, Pool, PoolGroup
|
||||||
from app.models.bridges import Bridge, BridgeConf
|
from app.models.bridges import Bridge, BridgeConf
|
||||||
from app.models.mirrors import Origin, Proxy, SmartProxy
|
from app.models.mirrors import Origin, Proxy, SmartProxy
|
||||||
from app.models.alarms import Alarm, AlarmState
|
from app.models.onions import Eotk, Onion
|
||||||
from app.models.onions import Onion, Eotk
|
|
||||||
from app.models.tfstate import TerraformState
|
from app.models.tfstate import TerraformState
|
||||||
|
|
||||||
Model = Type[db.Model] # type: ignore[name-defined]
|
Model = Type[db.Model] # type: ignore[name-defined]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from typing import Callable, Any
|
from typing import Any, Callable
|
||||||
|
|
||||||
from app import app
|
from app import app
|
||||||
from app.cli import _SubparserType, BaseCliHandler
|
from app.cli import BaseCliHandler, _SubparserType
|
||||||
from app.lists import lists
|
from app.lists import lists
|
||||||
from app.models.base import Pool
|
from app.models.base import Pool
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
from flask_bootstrap import Bootstrap5
|
||||||
from flask_migrate import Migrate
|
from flask_migrate import Migrate
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from flask_bootstrap import Bootstrap5
|
|
||||||
from sqlalchemy import MetaData
|
from sqlalchemy import MetaData
|
||||||
|
|
||||||
convention = {
|
convention = {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Dict, Callable, Any
|
from typing import Any, Callable, Dict
|
||||||
|
|
||||||
from app.lists.bc2 import mirror_sites
|
from app.lists.bc2 import mirror_sites
|
||||||
from app.lists.bridgelines import bridgelines
|
from app.lists.bridgelines import bridgelines
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import List, Optional, TypedDict
|
from typing import List, Optional, TypedDict
|
||||||
|
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
|
|
||||||
from app.models.base import Pool
|
from app.models.base import Pool
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import List, Dict, Optional, TypedDict
|
from typing import Dict, List, Optional, TypedDict
|
||||||
|
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
|
|
||||||
from app.models.base import Pool
|
from app.models.base import Pool
|
||||||
|
|
|
@ -7,6 +7,7 @@ from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from app.brm.brn import BRN
|
from app.brm.brn import BRN
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
|
from app.models.types import AwareDateTime
|
||||||
|
|
||||||
|
|
||||||
class AbstractConfiguration(db.Model): # type: ignore
|
class AbstractConfiguration(db.Model): # type: ignore
|
||||||
|
@ -14,9 +15,9 @@ class AbstractConfiguration(db.Model): # type: ignore
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
|
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
|
||||||
description: Mapped[str]
|
description: Mapped[str]
|
||||||
added: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
added: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
updated: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
updated: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
destroyed: Mapped[Optional[datetime]] = mapped_column(db.DateTime(timezone=True), nullable=True)
|
destroyed: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
@ -43,7 +44,7 @@ class Deprecation(db.Model): # type: ignore[name-defined,misc]
|
||||||
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
|
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
|
||||||
resource_type: Mapped[str]
|
resource_type: Mapped[str]
|
||||||
resource_id: Mapped[int]
|
resource_id: Mapped[int]
|
||||||
deprecated_at: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
deprecated_at: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
meta: Mapped[Optional[Dict[str, Any]]] = mapped_column(db.JSON())
|
meta: Mapped[Optional[Dict[str, Any]]] = mapped_column(db.JSON())
|
||||||
reason: Mapped[str]
|
reason: Mapped[str]
|
||||||
|
|
||||||
|
@ -58,11 +59,11 @@ class AbstractResource(db.Model): # type: ignore
|
||||||
__abstract__ = True
|
__abstract__ = True
|
||||||
|
|
||||||
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
|
id: Mapped[int] = mapped_column(db.Integer, primary_key=True)
|
||||||
added: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
added: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
updated: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
updated: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
deprecated: Mapped[Optional[datetime]] = mapped_column(db.DateTime(timezone=True), nullable=True)
|
deprecated: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||||
deprecation_reason: Mapped[Optional[str]]
|
deprecation_reason: Mapped[Optional[str]]
|
||||||
destroyed: Mapped[Optional[datetime]] = mapped_column(db.DateTime(timezone=True), nullable=True)
|
destroyed: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||||
|
|
||||||
def __init__(self, *,
|
def __init__(self, *,
|
||||||
id: Optional[int] = None,
|
id: Optional[int] = None,
|
||||||
|
|
|
@ -7,6 +7,7 @@ from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from app.brm.brn import BRN
|
from app.brm.brn import BRN
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models import AbstractConfiguration
|
from app.models import AbstractConfiguration
|
||||||
|
from app.models.types import AwareDateTime
|
||||||
|
|
||||||
|
|
||||||
class Activity(db.Model): # type: ignore
|
class Activity(db.Model): # type: ignore
|
||||||
|
@ -14,7 +15,7 @@ class Activity(db.Model): # type: ignore
|
||||||
group_id: Mapped[Optional[int]]
|
group_id: Mapped[Optional[int]]
|
||||||
activity_type: Mapped[str]
|
activity_type: Mapped[str]
|
||||||
text: Mapped[str]
|
text: Mapped[str]
|
||||||
added: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
added: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
|
|
||||||
def __init__(self, *,
|
def __init__(self, *,
|
||||||
id: Optional[int] = None,
|
id: Optional[int] = None,
|
||||||
|
|
|
@ -6,6 +6,7 @@ from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.activity import Activity
|
from app.models.activity import Activity
|
||||||
|
from app.models.types import AwareDateTime
|
||||||
|
|
||||||
|
|
||||||
class AlarmState(enum.Enum):
|
class AlarmState(enum.Enum):
|
||||||
|
@ -30,8 +31,8 @@ class Alarm(db.Model): # type: ignore
|
||||||
target: Mapped[str]
|
target: Mapped[str]
|
||||||
aspect: Mapped[str]
|
aspect: Mapped[str]
|
||||||
alarm_state: Mapped[AlarmState] = mapped_column(default=AlarmState.UNKNOWN)
|
alarm_state: Mapped[AlarmState] = mapped_column(default=AlarmState.UNKNOWN)
|
||||||
state_changed: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
state_changed: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
last_updated: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
last_updated: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
text: Mapped[str]
|
text: Mapped[str]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -7,6 +7,7 @@ from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from app.brm.brn import BRN
|
from app.brm.brn import BRN
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models import AbstractConfiguration, AbstractResource
|
from app.models import AbstractConfiguration, AbstractResource
|
||||||
|
from app.models.types import AwareDateTime
|
||||||
|
|
||||||
|
|
||||||
class AutomationState(enum.Enum):
|
class AutomationState(enum.Enum):
|
||||||
|
@ -19,8 +20,8 @@ class Automation(AbstractConfiguration):
|
||||||
short_name: Mapped[str]
|
short_name: Mapped[str]
|
||||||
state: Mapped[AutomationState] = mapped_column(default=AutomationState.IDLE)
|
state: Mapped[AutomationState] = mapped_column(default=AutomationState.IDLE)
|
||||||
enabled: Mapped[bool]
|
enabled: Mapped[bool]
|
||||||
last_run: Mapped[Optional[datetime]] = mapped_column(db.DateTime(timezone=True))
|
last_run: Mapped[Optional[datetime]] = mapped_column(AwareDateTime())
|
||||||
next_run: Mapped[Optional[datetime]] = mapped_column(db.DateTime(timezone=True))
|
next_run: Mapped[Optional[datetime]] = mapped_column(AwareDateTime())
|
||||||
next_is_full: Mapped[bool]
|
next_is_full: Mapped[bool]
|
||||||
|
|
||||||
logs = db.relationship("AutomationLogs", back_populates="automation")
|
logs = db.relationship("AutomationLogs", back_populates="automation")
|
||||||
|
|
|
@ -8,6 +8,7 @@ from app.brm.brn import BRN
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models import AbstractConfiguration, AbstractResource
|
from app.models import AbstractConfiguration, AbstractResource
|
||||||
from app.models.base import Pool
|
from app.models.base import Pool
|
||||||
|
from app.models.types import AwareDateTime
|
||||||
|
|
||||||
|
|
||||||
class ProviderAllocation(enum.Enum):
|
class ProviderAllocation(enum.Enum):
|
||||||
|
@ -54,7 +55,7 @@ class BridgeConf(AbstractConfiguration):
|
||||||
class Bridge(AbstractResource):
|
class Bridge(AbstractResource):
|
||||||
conf_id: Mapped[int] = mapped_column(db.ForeignKey("bridge_conf.id"))
|
conf_id: Mapped[int] = mapped_column(db.ForeignKey("bridge_conf.id"))
|
||||||
cloud_account_id: Mapped[int] = mapped_column(db.ForeignKey("cloud_account.id"))
|
cloud_account_id: Mapped[int] = mapped_column(db.ForeignKey("cloud_account.id"))
|
||||||
terraform_updated: Mapped[Optional[datetime]] = mapped_column(db.DateTime(timezone=True), nullable=True)
|
terraform_updated: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||||
nickname: Mapped[Optional[str]]
|
nickname: Mapped[Optional[str]]
|
||||||
fingerprint: Mapped[Optional[str]]
|
fingerprint: Mapped[Optional[str]]
|
||||||
hashed_fingerprint: Mapped[Optional[str]]
|
hashed_fingerprint: Mapped[Optional[str]]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import enum
|
import enum
|
||||||
from typing import Any, Dict, List, TYPE_CHECKING
|
from typing import TYPE_CHECKING, Any, Dict, List
|
||||||
|
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ from app.extensions import db
|
||||||
from app.models import AbstractConfiguration
|
from app.models import AbstractConfiguration
|
||||||
from app.models.mirrors import StaticOrigin
|
from app.models.mirrors import StaticOrigin
|
||||||
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from app.models.bridges import Bridge
|
from app.models.bridges import Bridge
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ from app.extensions import db
|
||||||
from app.models import AbstractConfiguration, AbstractResource, Deprecation
|
from app.models import AbstractConfiguration, AbstractResource, Deprecation
|
||||||
from app.models.base import Group, Pool
|
from app.models.base import Group, Pool
|
||||||
from app.models.onions import Onion
|
from app.models.onions import Onion
|
||||||
|
from app.models.types import AwareDateTime
|
||||||
|
|
||||||
country_origin = db.Table(
|
country_origin = db.Table(
|
||||||
'country_origin',
|
'country_origin',
|
||||||
|
@ -275,7 +276,7 @@ class Proxy(AbstractResource):
|
||||||
provider: Mapped[str] = mapped_column(db.String(20), nullable=False)
|
provider: Mapped[str] = mapped_column(db.String(20), nullable=False)
|
||||||
psg: Mapped[Optional[int]] = mapped_column(db.Integer, nullable=True)
|
psg: Mapped[Optional[int]] = mapped_column(db.Integer, nullable=True)
|
||||||
slug: Mapped[Optional[str]] = mapped_column(db.String(20), nullable=True)
|
slug: Mapped[Optional[str]] = mapped_column(db.String(20), nullable=True)
|
||||||
terraform_updated: Mapped[Optional[datetime]] = mapped_column(db.DateTime(timezone=True), nullable=True)
|
terraform_updated: Mapped[Optional[datetime]] = mapped_column(AwareDateTime(), nullable=True)
|
||||||
url: Mapped[Optional[str]] = mapped_column(db.String(255), nullable=True)
|
url: Mapped[Optional[str]] = mapped_column(db.String(255), nullable=True)
|
||||||
|
|
||||||
origin: Mapped[Origin] = relationship("Origin", back_populates="proxies")
|
origin: Mapped[Origin] = relationship("Origin", back_populates="proxies")
|
||||||
|
|
|
@ -7,6 +7,7 @@ from app.brm.brn import BRN
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models import AbstractConfiguration, AbstractResource
|
from app.models import AbstractConfiguration, AbstractResource
|
||||||
from app.models.base import Group
|
from app.models.base import Group
|
||||||
|
from app.models.types import AwareDateTime
|
||||||
from app.util.onion import onion_hostname
|
from app.util.onion import onion_hostname
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ class Onion(AbstractConfiguration):
|
||||||
|
|
||||||
group_id: Mapped[int] = mapped_column(db.ForeignKey("group.id"))
|
group_id: Mapped[int] = mapped_column(db.ForeignKey("group.id"))
|
||||||
domain_name: Mapped[str]
|
domain_name: Mapped[str]
|
||||||
cert_expiry: Mapped[datetime] = mapped_column(db.DateTime(timezone=True))
|
cert_expiry: Mapped[datetime] = mapped_column(AwareDateTime())
|
||||||
cert_sans: Mapped[str]
|
cert_sans: Mapped[str]
|
||||||
onion_public_key: Mapped[bytes]
|
onion_public_key: Mapped[bytes]
|
||||||
onion_private_key: Mapped[bytes]
|
onion_private_key: Mapped[bytes]
|
||||||
|
|
21
app/models/types.py
Normal file
21
app/models/types.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from datetime import timezone
|
||||||
|
|
||||||
|
from sqlalchemy import DateTime, TypeDecorator
|
||||||
|
|
||||||
|
|
||||||
|
class AwareDateTime(TypeDecorator):
|
||||||
|
impl = DateTime(timezone=True)
|
||||||
|
|
||||||
|
cache_ok = True
|
||||||
|
|
||||||
|
def process_bind_param(self, value, dialect):
|
||||||
|
# Ensure the value is aware. If it's naive, assume UTC.
|
||||||
|
if value is not None and value.tzinfo is None:
|
||||||
|
value = value.replace(tzinfo=timezone.utc)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def process_result_value(self, value, dialect):
|
||||||
|
# Ensure the value is aware. If it's naive, assume UTC.
|
||||||
|
if value is not None and value.tzinfo is None:
|
||||||
|
value = value.replace(tzinfo=timezone.utc)
|
||||||
|
return value
|
|
@ -1,6 +1,7 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from flask import render_template, Response, flash, redirect, url_for, Blueprint
|
from flask import (Blueprint, Response, flash, redirect, render_template,
|
||||||
|
url_for)
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
|
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from typing import List, Union, Optional, Dict, Type
|
from typing import Dict, List, Optional, Type, Union
|
||||||
|
|
||||||
from flask import render_template, url_for, redirect, Blueprint
|
from flask import Blueprint, redirect, render_template, url_for
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import SelectField, StringField, SubmitField, IntegerField, BooleanField, Form, FormField
|
from wtforms import (BooleanField, Form, FormField, IntegerField, SelectField,
|
||||||
|
StringField, SubmitField)
|
||||||
from wtforms.validators import InputRequired
|
from wtforms.validators import InputRequired
|
||||||
|
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import current_app, render_template, Blueprint, Response
|
from flask import Blueprint, Response, current_app, render_template
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, SubmitField, SelectField
|
from wtforms import SelectField, StringField, SubmitField
|
||||||
|
|
||||||
|
|
||||||
class EditMirrorForm(FlaskForm): # type: ignore
|
class EditMirrorForm(FlaskForm): # type: ignore
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from flask import redirect, Blueprint
|
from flask import Blueprint, redirect
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
|
|
||||||
from app.models.onions import Onion
|
from app.models.onions import Onion
|
||||||
|
|
|
@ -2,15 +2,16 @@ import logging
|
||||||
import secrets
|
import secrets
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from flask import render_template, url_for, flash, redirect, Response, Blueprint
|
import sqlalchemy
|
||||||
|
from flask import (Blueprint, Response, flash, redirect, render_template,
|
||||||
|
url_for)
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
import sqlalchemy
|
from wtforms import SelectField, StringField, SubmitField
|
||||||
from wtforms import StringField, SubmitField, SelectField
|
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.base import Pool, Group
|
from app.models.base import Group, Pool
|
||||||
from app.portal.util import LifecycleForm
|
from app.portal.util import LifecycleForm
|
||||||
|
|
||||||
bp = Blueprint("pool", __name__)
|
bp = Blueprint("pool", __name__)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from flask import render_template, Response, flash, redirect, url_for, Blueprint
|
from flask import (Blueprint, Response, flash, redirect, render_template,
|
||||||
|
url_for)
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import render_template, Blueprint
|
from flask import Blueprint, render_template
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from sqlalchemy import desc
|
from sqlalchemy import desc
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
import logging
|
import logging
|
||||||
from typing import Optional, List, Any
|
from typing import Any, List, Optional
|
||||||
|
|
||||||
import sqlalchemy.exc
|
import sqlalchemy.exc
|
||||||
from flask import flash, redirect, url_for, render_template, Response, Blueprint, current_app
|
from flask import (Blueprint, Response, current_app, flash, redirect,
|
||||||
|
render_template, url_for)
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from sqlalchemy import exc
|
from sqlalchemy import exc
|
||||||
from wtforms import StringField, SelectField, SubmitField, BooleanField, FileField
|
from wtforms import (BooleanField, FileField, SelectField, StringField,
|
||||||
|
SubmitField)
|
||||||
from wtforms.validators import DataRequired
|
from wtforms.validators import DataRequired
|
||||||
|
|
||||||
from app.brm.static import create_static_origin
|
from app.brm.static import create_static_origin
|
||||||
from app.models.base import Group
|
from app.models.base import Group
|
||||||
from app.models.cloud import CloudAccount, CloudProvider
|
from app.models.cloud import CloudAccount, CloudProvider
|
||||||
from app.models.mirrors import StaticOrigin, Origin
|
from app.models.mirrors import Origin, StaticOrigin
|
||||||
from app.portal.util import response_404, view_lifecycle
|
from app.portal.util import response_404, view_lifecycle
|
||||||
|
|
||||||
bp = Blueprint("static", __name__)
|
bp = Blueprint("static", __name__)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from flask import Response, render_template, flash, redirect, url_for
|
from flask import Response, flash, redirect, render_template, url_for
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import SubmitField
|
from wtforms import SubmitField
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
from typing import Tuple, Any, Optional
|
from typing import Any, Optional, Tuple
|
||||||
from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED
|
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo
|
||||||
|
|
||||||
import jinja2
|
import jinja2
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Tuple, Optional
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import boto3
|
import boto3
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
@ -6,8 +6,8 @@ from sqlalchemy import func
|
||||||
from app import app
|
from app import app
|
||||||
from app.alarms import get_or_create_alarm
|
from app.alarms import get_or_create_alarm
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.base import Group
|
|
||||||
from app.models.alarms import AlarmState
|
from app.models.alarms import AlarmState
|
||||||
|
from app.models.base import Group
|
||||||
from app.models.onions import Eotk
|
from app.models.onions import Eotk
|
||||||
from app.terraform import BaseAutomation
|
from app.terraform import BaseAutomation
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ from app import app
|
||||||
from app.alarms import get_or_create_alarm
|
from app.alarms import get_or_create_alarm
|
||||||
from app.brm.brn import BRN
|
from app.brm.brn import BRN
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.mirrors import Proxy
|
|
||||||
from app.models.alarms import AlarmState
|
from app.models.alarms import AlarmState
|
||||||
|
from app.models.mirrors import Proxy
|
||||||
from app.terraform import BaseAutomation
|
from app.terraform import BaseAutomation
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Tuple, Optional
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
import boto3
|
import boto3
|
||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
|
@ -6,8 +6,8 @@ from sqlalchemy import func
|
||||||
from app import app
|
from app import app
|
||||||
from app.alarms import get_or_create_alarm
|
from app.alarms import get_or_create_alarm
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.base import Group
|
|
||||||
from app.models.alarms import AlarmState
|
from app.models.alarms import AlarmState
|
||||||
|
from app.models.base import Group
|
||||||
from app.models.mirrors import SmartProxy
|
from app.models.mirrors import SmartProxy
|
||||||
from app.terraform import BaseAutomation
|
from app.terraform import BaseAutomation
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from github import Github
|
from github import Github
|
||||||
|
|
||||||
from app.terraform.block.bridge_reachability import BlockBridgeReachabilityAutomation
|
from app.terraform.block.bridge_reachability import \
|
||||||
|
BlockBridgeReachabilityAutomation
|
||||||
|
|
||||||
|
|
||||||
class BlockBridgeGitHubAutomation(BlockBridgeReachabilityAutomation):
|
class BlockBridgeGitHubAutomation(BlockBridgeReachabilityAutomation):
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from gitlab import Gitlab
|
from gitlab import Gitlab
|
||||||
|
|
||||||
from app.terraform.block.bridge_reachability import BlockBridgeReachabilityAutomation
|
from app.terraform.block.bridge_reachability import \
|
||||||
|
BlockBridgeReachabilityAutomation
|
||||||
|
|
||||||
|
|
||||||
class BlockBridgeGitlabAutomation(BlockBridgeReachabilityAutomation):
|
class BlockBridgeGitlabAutomation(BlockBridgeReachabilityAutomation):
|
||||||
|
|
|
@ -2,7 +2,7 @@ import json
|
||||||
import logging
|
import logging
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
from zipfile import ZipFile, BadZipFile
|
from zipfile import BadZipFile, ZipFile
|
||||||
|
|
||||||
import lxml # nosec: B410
|
import lxml # nosec: B410
|
||||||
import requests
|
import requests
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from collections.abc import Mapping, Sequence
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from typing import List, Any
|
from collections.abc import Mapping, Sequence
|
||||||
|
from typing import Any, List
|
||||||
|
|
||||||
from app import app
|
from app import app
|
||||||
from app.lists import lists
|
from app.lists import lists
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
|
import datetime
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
import datetime
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Optional, Any, List, Dict
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
@ -11,7 +11,7 @@ from sqlalchemy import text
|
||||||
from app import app
|
from app import app
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.base import Group
|
from app.models.base import Group
|
||||||
from app.models.mirrors import Proxy, Origin, SmartProxy
|
from app.models.mirrors import Origin, Proxy, SmartProxy
|
||||||
from app.terraform.terraform import TerraformAutomation
|
from app.terraform.terraform import TerraformAutomation
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from typing import Optional, Any
|
from typing import Any, Optional
|
||||||
|
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models.mirrors import Proxy
|
from app.models.mirrors import Proxy
|
||||||
|
|
|
@ -235,6 +235,7 @@ class ProxyMetaAutomation(BaseAutomation):
|
||||||
"""
|
"""
|
||||||
pools = Pool.query.all()
|
pools = Pool.query.all()
|
||||||
for pool in pools:
|
for pool in pools:
|
||||||
|
logging.debug(pool.added < datetime.now(tz=timezone.utc))
|
||||||
if pool.id == -1:
|
if pool.id == -1:
|
||||||
continue # Skip hotspare pool
|
continue # Skip hotspare pool
|
||||||
logging.debug("Missing proxy check for %s", pool.pool_name)
|
logging.debug("Missing proxy check for %s", pool.pool_name)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from flask import Blueprint, request, Response
|
from flask import Blueprint, Response, request
|
||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
|
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
from typing import Tuple, Optional, List, Dict
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
def onion_hostname(onion_public_key: bytes) -> str:
|
def onion_hostname(onion_public_key: bytes) -> str:
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import ssl
|
import ssl
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Optional, Tuple, List, Dict, TYPE_CHECKING
|
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
from cryptography.hazmat._oid import ExtensionOID
|
from cryptography.hazmat._oid import ExtensionOID
|
||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric import rsa, padding
|
from cryptography.hazmat.primitives.asymmetric import padding, rsa
|
||||||
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
|
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
|
||||||
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
|
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
|
||||||
|
|
||||||
|
|
85
migrations/versions/cb3d6f0cdb86_switch_to_timezone_aware.py
Normal file
85
migrations/versions/cb3d6f0cdb86_switch_to_timezone_aware.py
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
"""switch to timezone aware
|
||||||
|
|
||||||
|
Revision ID: cb3d6f0cdb86
|
||||||
|
Revises: 54b31e87fe33
|
||||||
|
Create Date: 2024-12-06 17:34:51.630311
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'cb3d6f0cdb86'
|
||||||
|
down_revision = '54b31e87fe33'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
def alter_column_to_timezone_aware(table_name, column_name):
|
||||||
|
with op.batch_alter_table(table_name, schema=None) as batch_op:
|
||||||
|
batch_op.alter_column(
|
||||||
|
column_name,
|
||||||
|
type_=sa.DateTime(timezone=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
# AbstractConfiguration derived tables
|
||||||
|
configuration_tables = [
|
||||||
|
"automation",
|
||||||
|
"cloud_account",
|
||||||
|
"bridge_conf",
|
||||||
|
"country",
|
||||||
|
"group",
|
||||||
|
"mirror_list",
|
||||||
|
"onion",
|
||||||
|
"origin",
|
||||||
|
"pool",
|
||||||
|
"static_origin",
|
||||||
|
"webhook"
|
||||||
|
]
|
||||||
|
for t in configuration_tables:
|
||||||
|
alter_column_to_timezone_aware(t, 'added')
|
||||||
|
alter_column_to_timezone_aware(t, 'updated')
|
||||||
|
alter_column_to_timezone_aware(t, 'destroyed')
|
||||||
|
|
||||||
|
# AbstractResource derived tables
|
||||||
|
resource_tables = [
|
||||||
|
"bridge",
|
||||||
|
"proxy",
|
||||||
|
"smart_proxy",
|
||||||
|
"automation_logs",
|
||||||
|
"eotk"
|
||||||
|
]
|
||||||
|
for t in resource_tables:
|
||||||
|
alter_column_to_timezone_aware(t, 'added')
|
||||||
|
alter_column_to_timezone_aware(t, 'updated')
|
||||||
|
alter_column_to_timezone_aware(t, 'deprecated')
|
||||||
|
alter_column_to_timezone_aware(t, 'destroyed')
|
||||||
|
|
||||||
|
# Deprecation
|
||||||
|
alter_column_to_timezone_aware("deprecation", "deprecated_at")
|
||||||
|
|
||||||
|
# Activity
|
||||||
|
alter_column_to_timezone_aware("activity", "added")
|
||||||
|
|
||||||
|
# Alarm
|
||||||
|
alter_column_to_timezone_aware("alarm", "state_changed")
|
||||||
|
alter_column_to_timezone_aware("alarm", "last_updated")
|
||||||
|
|
||||||
|
# Bridge terraform_updated
|
||||||
|
alter_column_to_timezone_aware("bridge", "terraform_updated")
|
||||||
|
|
||||||
|
# Proxy terraform_updated
|
||||||
|
alter_column_to_timezone_aware("proxy", "terraform_updated")
|
||||||
|
|
||||||
|
# Automation last_run, next_run
|
||||||
|
alter_column_to_timezone_aware("automation", "last_run")
|
||||||
|
alter_column_to_timezone_aware("automation", "next_run")
|
||||||
|
|
||||||
|
# Onion cert_expiry
|
||||||
|
alter_column_to_timezone_aware("onion", "cert_expiry")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
pass
|
Loading…
Add table
Add a link
Reference in a new issue