This commit replaces the usage of PatchingClient, following the changes from 1. It also, additionally, removes the sync status 'not-available' and updates the software audit to use the software_audit_requested column in the subcloud_audits table. Test plan: 1. PASS: Deploy a DC system. 2. PASS: Manage a subcloud and verify that all endpoints are set as 'in-sync'. 4. PASS: Unmanage a subcloud and verify that all endpoints are set as 'unknown'. 5. PASS: Leave audit running for a while and ensure that there are no errors logged. 6. PASS: Verify that the 'dcmanager subcloud list' command appropriately displays the resulting sync-status column based on the audit status of each endpoint. 7. PASS: In a newly installed system, execute a select statement in the subcloud_audits table and verify that the software_audit_requested column exists and it is filled with False by default. 8. PASS: Apply the migrations in an already deployed system and verify that the values in spare_audit_requested are moved to software_audit_request in the subcloud_audits table. 9. PASS: Upload an iso using the dcorch proxy and verify it completes successfully. 10. PASS: Perform a system upgrade successfully. [1] https://review.opendev.org/c/starlingx/distcloud/+/949363 Story: 2011311 Task: 52197 Change-Id: I8837c1f4faf308d2a380c0133121427de6ed64a2 Signed-off-by: Raphael <Raphael.Lima@windriver.com>
303 lines
10 KiB
Python
303 lines
10 KiB
Python
# Copyright (c) 2015 Ericsson AB
|
|
# Copyright (c) 2017-2025 Wind River Systems, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# 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.
|
|
#
|
|
|
|
"""
|
|
SQLAlchemy models for dcmanager data.
|
|
"""
|
|
|
|
import datetime
|
|
import json
|
|
|
|
from oslo_db.sqlalchemy import models
|
|
from sqlalchemy import Boolean
|
|
from sqlalchemy import Column
|
|
from sqlalchemy import DateTime
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|
from sqlalchemy import ForeignKey
|
|
from sqlalchemy import Integer
|
|
from sqlalchemy.orm import backref
|
|
from sqlalchemy.orm import relationship
|
|
from sqlalchemy.orm import session as orm_session
|
|
from sqlalchemy import String
|
|
from sqlalchemy import Text
|
|
from sqlalchemy.types import TypeDecorator
|
|
from sqlalchemy.types import VARCHAR
|
|
|
|
BASE = declarative_base()
|
|
|
|
|
|
def get_session():
|
|
from dcmanager.db.sqlalchemy import api as db_api
|
|
|
|
return db_api.get_session()
|
|
|
|
|
|
class JSONEncodedDict(TypeDecorator):
|
|
"""Represents an immutable structure as a json-encoded string."""
|
|
|
|
impl = VARCHAR
|
|
|
|
def process_bind_param(self, value, dialect):
|
|
if value is not None:
|
|
value = json.dumps(value)
|
|
return value
|
|
|
|
def process_result_value(self, value, dialect):
|
|
if value is not None:
|
|
value = json.loads(value)
|
|
return value
|
|
|
|
|
|
class DCManagerBase(models.ModelBase, models.SoftDeleteMixin, models.TimestampMixin):
|
|
"""Base class for DC Manager Models."""
|
|
|
|
# __table_args__ = {'mysql_engine': 'InnoDB'}
|
|
|
|
def expire(self, session=None, attrs=None):
|
|
if not session:
|
|
session = orm_session.Session.object_session(self)
|
|
if not session:
|
|
session = get_session()
|
|
session.expire(self, attrs)
|
|
|
|
def refresh(self, session=None, attrs=None):
|
|
"""Refresh this object."""
|
|
if not session:
|
|
session = orm_session.Session.object_session(self)
|
|
if not session:
|
|
session = get_session()
|
|
session.refresh(self, attrs)
|
|
|
|
def delete(self, session=None):
|
|
"""Delete this object."""
|
|
if not session:
|
|
session = orm_session.Session.object_session(self)
|
|
if not session:
|
|
session = get_session()
|
|
session.begin()
|
|
session.delete(self)
|
|
session.commit()
|
|
|
|
|
|
class SystemPeer(BASE, DCManagerBase):
|
|
"""Represents a system peer"""
|
|
|
|
__tablename__ = "system_peer"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
|
|
peer_uuid = Column(String(36), unique=True)
|
|
peer_name = Column(String(255), unique=True)
|
|
manager_endpoint = Column(String(255))
|
|
manager_username = Column(String(255))
|
|
manager_password = Column(String(255))
|
|
peer_controller_gateway_ip = Column(String(255))
|
|
administrative_state = Column(String(255))
|
|
heartbeat_interval = Column(Integer)
|
|
heartbeat_failure_threshold = Column(Integer)
|
|
heartbeat_failure_policy = Column(String(255))
|
|
heartbeat_maintenance_timeout = Column(Integer)
|
|
availability_state = Column(String(255))
|
|
|
|
|
|
class SubcloudGroup(BASE, DCManagerBase):
|
|
"""Represents a subcloud group"""
|
|
|
|
__tablename__ = "subcloud_group"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
|
|
name = Column(String(255), unique=True)
|
|
description = Column(String(255))
|
|
update_apply_type = Column(String(255))
|
|
max_parallel_subclouds = Column(Integer)
|
|
|
|
|
|
class SubcloudPeerGroup(BASE, DCManagerBase):
|
|
"""Represents a subcloud group"""
|
|
|
|
__tablename__ = "subcloud_peer_group"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
|
|
peer_group_name = Column(String(255), unique=True)
|
|
group_priority = Column(Integer)
|
|
group_state = Column(String(255))
|
|
max_subcloud_rehoming = Column(Integer)
|
|
system_leader_id = Column(String(255))
|
|
system_leader_name = Column(String(255))
|
|
migration_status = Column(String(255))
|
|
|
|
|
|
class PeerGroupAssociation(BASE, DCManagerBase):
|
|
"""Represents a Peer Group Association"""
|
|
|
|
__tablename__ = "peer_group_association"
|
|
|
|
id = Column(Integer, primary_key=True, autoincrement=True, nullable=False)
|
|
peer_group_id = Column(Integer)
|
|
system_peer_id = Column(Integer)
|
|
association_type = Column(String(255))
|
|
peer_group_priority = Column(Integer)
|
|
sync_status = Column(String(255))
|
|
sync_message = Column(Text())
|
|
|
|
|
|
class Subcloud(BASE, DCManagerBase):
|
|
"""Represents a subcloud"""
|
|
|
|
__tablename__ = "subclouds"
|
|
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
name = Column(String(255), unique=True)
|
|
description = Column(String(255))
|
|
location = Column(String(255))
|
|
software_version = Column(String(255))
|
|
management_state = Column(String(255))
|
|
availability_status = Column(String(255))
|
|
data_install = Column(String())
|
|
deploy_status = Column(String(255))
|
|
backup_status = Column(String(255))
|
|
backup_datetime = Column(DateTime(timezone=False))
|
|
error_description = Column(String(2048))
|
|
region_name = Column(String(255), unique=True)
|
|
data_upgrade = Column(String())
|
|
management_subnet = Column(String(255))
|
|
management_gateway_ip = Column(String(255))
|
|
management_start_ip = Column(String(255), unique=True)
|
|
management_end_ip = Column(String(255), unique=True)
|
|
openstack_installed = Column(Boolean, nullable=False, default=False)
|
|
systemcontroller_gateway_ip = Column(String(255))
|
|
external_oam_subnet_ip_family = Column(String(255))
|
|
audit_fail_count = Column(Integer)
|
|
first_identity_sync_complete = Column(Boolean, default=False)
|
|
peer_group_id = Column(Integer, ForeignKey("subcloud_peer_group.id"))
|
|
rehome_data = Column(Text())
|
|
prestage_status = Column(String(255))
|
|
prestage_versions = Column(String(255))
|
|
|
|
# multiple subclouds can be in a particular group
|
|
group_id = Column(Integer, ForeignKey("subcloud_group.id"))
|
|
group = relationship(SubcloudGroup, backref=backref("subcloud"))
|
|
rehomed = Column(Boolean, default=False)
|
|
|
|
|
|
class SubcloudAudits(BASE, DCManagerBase):
|
|
"""Represents the various audits for a subcloud"""
|
|
|
|
__tablename__ = "subcloud_audits"
|
|
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
subcloud_id = Column(
|
|
Integer, ForeignKey("subclouds.id", ondelete="CASCADE"), unique=True
|
|
)
|
|
audit_started_at = Column(DateTime(timezone=False), default=datetime.datetime.min)
|
|
audit_finished_at = Column(DateTime(timezone=False), default=datetime.datetime.min)
|
|
state_update_requested = Column(Boolean, nullable=False, default=False)
|
|
firmware_audit_requested = Column(Boolean, nullable=False, default=False)
|
|
kubernetes_audit_requested = Column(Boolean, nullable=False, default=False)
|
|
kube_rootca_update_audit_requested = Column(Boolean, nullable=False, default=False)
|
|
software_audit_requested = Column(Boolean, nullable=False, default=False)
|
|
spare_audit_requested = Column(Boolean, nullable=False, default=False)
|
|
spare2_audit_requested = Column(Boolean, nullable=False, default=False)
|
|
reserved = Column(Text)
|
|
|
|
|
|
class SubcloudStatus(BASE, DCManagerBase):
|
|
"""Represents the status of an endpoint in a subcloud"""
|
|
|
|
__tablename__ = "subcloud_status"
|
|
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
subcloud_id = Column(Integer, ForeignKey("subclouds.id", ondelete="CASCADE"))
|
|
endpoint_type = Column(String(255))
|
|
sync_status = Column(String(255))
|
|
|
|
|
|
class SwUpdateStrategy(BASE, DCManagerBase):
|
|
"""Represents a software update for subclouds"""
|
|
|
|
__tablename__ = "sw_update_strategy"
|
|
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
type = Column(String(255), unique=True)
|
|
subcloud_apply_type = Column(String(255))
|
|
max_parallel_subclouds = Column(Integer)
|
|
stop_on_failure = Column(Boolean)
|
|
state = Column(String(255))
|
|
extra_args = Column(JSONEncodedDict)
|
|
|
|
|
|
class SwUpdateOpts(BASE, DCManagerBase):
|
|
"""Represents software update options for a subcloud"""
|
|
|
|
__tablename__ = "sw_update_opts"
|
|
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
subcloud_id = Column(Integer, ForeignKey("subclouds.id", ondelete="CASCADE"))
|
|
|
|
storage_apply_type = Column(String(255))
|
|
worker_apply_type = Column(String(255))
|
|
max_parallel_workers = Column(Integer)
|
|
alarm_restriction_type = Column(String(255))
|
|
default_instance_action = Column(String(255))
|
|
|
|
|
|
class SwUpdateOptsDefault(BASE, DCManagerBase):
|
|
"""Represents default software update options for subclouds"""
|
|
|
|
__tablename__ = "sw_update_opts_default"
|
|
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
|
|
subcloud_id = Column(Integer)
|
|
storage_apply_type = Column(String(255))
|
|
worker_apply_type = Column(String(255))
|
|
max_parallel_workers = Column(Integer)
|
|
alarm_restriction_type = Column(String(255))
|
|
default_instance_action = Column(String(255))
|
|
|
|
|
|
class StrategyStep(BASE, DCManagerBase):
|
|
"""Represents a step for a strategy application"""
|
|
|
|
__tablename__ = "strategy_steps"
|
|
|
|
id = Column(Integer, primary_key=True, nullable=False)
|
|
subcloud_id = Column(
|
|
Integer, ForeignKey("subclouds.id", ondelete="CASCADE"), unique=True
|
|
)
|
|
stage = Column(Integer)
|
|
state = Column(String(255))
|
|
details = Column(String(1000))
|
|
started_at = Column(DateTime)
|
|
finished_at = Column(DateTime)
|
|
subcloud = relationship(
|
|
"Subcloud", backref=backref("strategy_steps", cascade="all,delete")
|
|
)
|
|
|
|
|
|
class SubcloudAlarmSummary(BASE, DCManagerBase):
|
|
"""Represents a Distributed Cloud subcloud alarm aggregate"""
|
|
|
|
__tablename__ = "subcloud_alarms"
|
|
id = Column(Integer, primary_key=True, nullable=False, autoincrement=True)
|
|
uuid = Column(String(36), unique=True)
|
|
name = Column("name", String(255), unique=True)
|
|
critical_alarms = Column("critical_alarms", Integer)
|
|
major_alarms = Column("major_alarms", Integer)
|
|
minor_alarms = Column("minor_alarms", Integer)
|
|
warnings = Column("warnings", Integer)
|
|
cloud_status = Column("cloud_status", String(64))
|