Example #1
0
class NodeBondInterface(Base):
    __tablename__ = 'node_bond_interfaces'
    id = Column(Integer, primary_key=True)
    node_id = Column(Integer,
                     ForeignKey('nodes.id', ondelete="CASCADE"),
                     nullable=False)
    name = Column(String(32), nullable=False)
    mac = Column(psql.MACADDR)
    assigned_networks_list = relationship(
        "NetworkGroup",
        secondary=NetworkBondAssignment.__table__,
        order_by="NetworkGroup.id")
    state = Column(String(25))
    interface_properties = Column(MutableDict.as_mutable(JSON),
                                  default={},
                                  nullable=False,
                                  server_default='{}')
    mode = Column(Enum(*consts.BOND_MODES, name='bond_mode'),
                  nullable=False,
                  default=consts.BOND_MODES.active_backup)
    bond_properties = Column(MutableDict.as_mutable(JSON),
                             default={},
                             nullable=False,
                             server_default='{}')
    slaves = relationship("NodeNICInterface", backref="bond")
    attributes = Column(MutableDict.as_mutable(JSON),
                        default={},
                        server_default='{}',
                        nullable=False)

    @property
    def max_speed(self):
        return None

    @property
    def current_speed(self):
        return None

    @property
    def type(self):
        return consts.NETWORK_INTERFACE_TYPES.bond

    @property
    def assigned_networks(self):
        return [{
            "id": n.id,
            "name": n.name
        } for n in self.assigned_networks_list]

    @assigned_networks.setter
    def assigned_networks(self, value):
        self.assigned_networks_list = value
Example #2
0
class Plugin(Base):

    __tablename__ = 'plugins'

    __table_args__ = (
        UniqueConstraint('name', 'version', name='_name_version_unique'),)

    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)
    title = Column(String(100), nullable=False)
    version = Column(String(32), nullable=False)
    description = Column(String(400))
    releases = Column(MutableList.as_mutable(JSON), default=[])
    fuel_version = Column(MutableList.as_mutable(JSON), default=[])
    groups = Column(
        MutableList.as_mutable(JSON), server_default='[]', nullable=False)
    authors = Column(
        MutableList.as_mutable(JSON), server_default='[]', nullable=False)
    licenses = Column(
        MutableList.as_mutable(JSON), server_default='[]', nullable=False)
    homepage = Column(Text, nullable=True)
    package_version = Column(String(32), nullable=False)
    is_hotpluggable = Column(Boolean, default=False)
    attributes_metadata = Column(
        MutableDict.as_mutable(JSON), server_default='{}', nullable=False)
    volumes_metadata = Column(
        MutableDict.as_mutable(JSON), server_default='{}', nullable=False)
    roles_metadata = Column(
        MutableDict.as_mutable(JSON), server_default='{}', nullable=False)
    network_roles_metadata = Column(
        MutableList.as_mutable(JSON), server_default='[]', nullable=False)
    components_metadata = Column(
        MutableList.as_mutable(JSON), server_default='[]')
    # TODO(apopovych): To support old plugins versions we need separate
    # tasks which runs directly during deployment(stored in `deployment_tasks`
    # attribute) and which executes before/after of deployment process
    # (also called pre/post deployment tasks and stored in `tasks`
    # attribute). In future `deployment_tasks` and `tasks` should have
    # one format and this attribute will be removed.
    # Will be deprecated since plugins v5

    # (ikutukov) tasks yaml will stay here till fuel EOL to support upgrades
    # with old environments and old plugins.
    tasks = Column(
        MutableList.as_mutable(JSON), server_default='[]', nullable=False)
    clusters = relationship("Cluster",
                            secondary=ClusterPlugins.__table__,
                            backref="plugins")
    links = relationship(
        "PluginLink", backref="plugin", cascade="delete")
Example #3
0
class NodeNICInterface(Base):
    __tablename__ = 'node_nic_interfaces'
    id = Column(Integer, primary_key=True)
    node_id = Column(Integer,
                     ForeignKey('nodes.id', ondelete="CASCADE"),
                     nullable=False)
    name = Column(String(128), nullable=False)
    mac = Column(psql.MACADDR, nullable=False)
    max_speed = Column(Integer)
    current_speed = Column(Integer)
    assigned_networks_list = relationship(
        "NetworkGroup",
        secondary=NetworkNICAssignment.__table__,
        order_by="NetworkGroup.id")
    ip_addr = Column(psql.INET)
    netmask = Column(psql.INET)
    state = Column(String(25))
    interface_properties = Column(MutableDict.as_mutable(JSON),
                                  default={},
                                  nullable=False,
                                  server_default='{}')
    parent_id = Column(
        Integer, ForeignKey('node_bond_interfaces.id', ondelete='SET NULL'))
    driver = Column(Text)
    bus_info = Column(Text)
    pxe = Column(Boolean, default=False, nullable=False)
    attributes = Column(MutableDict.as_mutable(JSON),
                        default={},
                        server_default='{}',
                        nullable=False)
    meta = Column(MutableDict.as_mutable(JSON),
                  default={},
                  server_default='{}',
                  nullable=False)

    @property
    def type(self):
        return consts.NETWORK_INTERFACE_TYPES.ether

    @property
    def assigned_networks(self):
        return [{
            "id": n.id,
            "name": n.name
        } for n in self.assigned_networks_list]

    @assigned_networks.setter
    def assigned_networks(self, value):
        self.assigned_networks_list = value
Example #4
0
class NodeBondInterfaceClusterPlugin(Base):
    """Operates with Bond data from plugins

    Example (fetch plugin data for specific bond):
        db().query(
            NodeBondInterfaceClusterPlugin
        ).join(
            models.ClusterPlugin,
        ).filter(
            NodeBondInterfaceClusterPlugin.bond_id == bond_id
        ).filter(
            models.ClusterPlugin.enabled.is_(True)).all()
    """

    __tablename__ = 'node_bond_interface_cluster_plugins'

    id = Column(Integer, primary_key=True)
    cluster_plugin_id = Column(Integer,
                               ForeignKey('cluster_plugins.id',
                                          ondelete='CASCADE'),
                               nullable=False)
    bond_id = Column(Integer,
                     ForeignKey('node_bond_interfaces.id', ondelete='CASCADE'),
                     nullable=False)
    node_id = Column(Integer,
                     ForeignKey('nodes.id', ondelete='CASCADE'),
                     nullable=False)
    attributes = Column(MutableDict.as_mutable(JSON),
                        nullable=False,
                        server_default='{}')
    node = relationship("Node",
                        backref=backref("node_bond_interface_cluster_plugins",
                                        cascade="delete"))
Example #5
0
class ClusterPlugin(Base):

    __tablename__ = 'cluster_plugins'

    id = Column(Integer, primary_key=True)
    plugin_id = Column(Integer,
                       ForeignKey('plugins.id', ondelete='CASCADE'),
                       nullable=False)
    cluster_id = Column(Integer,
                        ForeignKey('clusters.id', ondelete='CASCADE'),
                        nullable=False)
    enabled = Column(Boolean,
                     nullable=False,
                     default=False,
                     server_default='false')
    # Initially, 'attributes' is a copy of 'Plugin.attributes_metadata'.
    # We need this column in order to store in there the modified (by user)
    # version of attributes, because we don't want to store them in cluster
    # attributes with no chance to remove.
    attributes = Column(MutableDict.as_mutable(JSON),
                        nullable=False,
                        server_default='{}')
    cluster = relationship("Cluster",
                           backref=backref("cluster_plugins",
                                           cascade="delete"))
    plugin = relationship("Plugin",
                          backref=backref("cluster_plugins", cascade="delete"))
Example #6
0
class MasterNodeSettings(Base):
    __tablename__ = 'master_node_settings'

    id = Column(Integer, primary_key=True)
    master_node_uid = Column(String(36), nullable=False)
    settings = Column(MutableDict.as_mutable(JSON),
                      nullable=False,
                      default={},
                      server_default='{}')
Example #7
0
    def test_deep_copy(self, m_changed):
        dct = MutableDict({'1': 'element1', '2': 'element2'})
        self.mutable_obj['2'] = dct

        m_changed.reset_mock()
        clone = deepcopy(self.mutable_obj)
        self.assertEqual(0, m_changed.call_count)
        dct['1'] = 'new_element'
        self.assertEqual(clone['2']['1'], 'element1')
        self.assertEqual(self.mutable_obj['2']['1'], 'new_element')
Example #8
0
class DeploymentGraph(Base):
    __tablename__ = 'deployment_graphs'
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(
        # not planned to used in business logic and
        # added to make work with custom graphs convenient
        sa.String(255),
        nullable=True)

    # contains YAQL expression to select nodes for applying the graph
    node_filter = sa.Column(sa.String(4096), nullable=True)

    # contains attributes which will be applied to appropriate object
    # if execution of graph completes successfully.
    on_success = sa.Column(MutableDict.as_mutable(JSON), nullable=True)
    # contains attributes which will be applied to appropriate object
    # if execution of graph fails.
    on_error = sa.Column(MutableDict.as_mutable(JSON), nullable=True)
    # contains attributes which will be applied to appropriate object
    # if execution of graph interrupts.
    on_stop = sa.Column(MutableDict.as_mutable(JSON), nullable=True)
Example #9
0
class NetworkingConfig(Base):
    __tablename__ = 'networking_configs'

    id = Column(Integer, primary_key=True)
    discriminator = Column(String(50))
    cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete="CASCADE"))
    dns_nameservers = Column(MutableList.as_mutable(JSON),
                             default=["8.8.4.4", "8.8.8.8"])
    floating_ranges = Column(MutableList.as_mutable(JSON), default=[])
    configuration_template = Column(MutableDict.as_mutable(JSON),
                                    nullable=True)
    __mapper_args__ = {'polymorphic_on': discriminator}
Example #10
0
class TestMutableDict(BaseUnitTest):
    def setUp(self):
        self.standard = {'1': 1}
        self.mutable_dict = MutableDict()
        self.mutable_dict.update(self.standard)

    def test_pop_existing(self, m_changed):
        self.assertEqual(self.mutable_dict.pop('1'), self.standard.pop('1'))
        m_changed.assert_called_once_with()

    def test_pop_existing_with_default(self, m_changed):
        self.assertEqual(self.mutable_dict.pop('1', None),
                         self.standard.pop('1', None))
        m_changed.assert_called_once_with()

    def test_pop_not_existing(self, m_changed):
        self.assertRaises(KeyError, self.mutable_dict.pop, '2')
        self.assertFalse(m_changed.called)

    def test_pop_not_existing_with_default(self, m_changed):
        self.assertEqual(self.mutable_dict.pop('2', {}),
                         self.standard.pop('2', {}))
        m_changed.assert_called_once_with()

    def test_popitem(self, m_changed):
        self.assertItemsEqual(self.mutable_dict.popitem(),
                              self.standard.popitem())
        m_changed.assert_called_once_with()

        m_changed.reset_mock()
        self.assertRaises(KeyError, self.mutable_dict.popitem)
        self.assertFalse(m_changed.called)
Example #11
0
class TestMutableDict(BaseUnitTest):
    def setUp(self):
        self.standard = {'1': 1}
        self.mutable_dict = MutableDict()
        self.mutable_dict.update(self.standard)

    def test_pop_existing(self, m_changed):
        self.assertEqual(self.mutable_dict.pop('1'), self.standard.pop('1'))
        m_changed.assert_called_once_with()

    def test_pop_existing_with_default(self, m_changed):
        self.assertEqual(self.mutable_dict.pop('1', None),
                         self.standard.pop('1', None))
        m_changed.assert_called_once_with()

    def test_pop_not_existing(self, m_changed):
        self.assertRaises(KeyError, self.mutable_dict.pop, '2')
        self.assertFalse(m_changed.called)

    def test_pop_not_existing_with_default(self, m_changed):
        self.assertEqual(self.mutable_dict.pop('2', {}),
                         self.standard.pop('2', {}))
        m_changed.assert_called_once_with()

    def test_popitem(self, m_changed):
        self.assertItemsEqual(self.mutable_dict.popitem(),
                              self.standard.popitem())
        m_changed.assert_called_once_with()

        m_changed.reset_mock()
        self.assertRaises(KeyError, self.mutable_dict.popitem)
        self.assertFalse(m_changed.called)
Example #12
0
class TestMutableDictCoerce(BaseUnitTest):
    def setUp(self):
        super(TestMutableDictCoerce, self).setUp()
        self.mutable_dict = MutableDict()

    def test_coerce_mutable_dict(self, m_coerce):
        dct = MutableDict()
        self.assertIsInstance(
            self.mutable_dict.coerce('key', dct), MutableDict)
        self.assertFalse(m_coerce.called)

    def test_coerce_dict(self, m_coerce):
        dct = dict()
        self.assertIsInstance(
            self.mutable_dict.coerce('key', dct), MutableDict)
        self.assertFalse(m_coerce.called)

    def test_coerce_not_acceptable_object(self, m_coerce):
        m_coerce.return_value = None
        obj = list()
        self.mutable_dict.coerce('key', obj)
        m_coerce.assert_called_once_with('key', obj)
Example #13
0
class TestMutableDictCoerce(BaseUnitTest):
    def setUp(self):
        super(TestMutableDictCoerce, self).setUp()
        self.mutable_dict = MutableDict()

    def test_coerce_mutable_dict(self, m_coerce):
        dct = MutableDict()
        self.assertIsInstance(self.mutable_dict.coerce('key', dct),
                              MutableDict)
        self.assertFalse(m_coerce.called)

    def test_coerce_dict(self, m_coerce):
        dct = dict()
        self.assertIsInstance(self.mutable_dict.coerce('key', dct),
                              MutableDict)
        self.assertFalse(m_coerce.called)

    def test_coerce_not_acceptable_object(self, m_coerce):
        m_coerce.return_value = None
        obj = list()
        self.mutable_dict.coerce('key', obj)
        m_coerce.assert_called_once_with('key', obj)
class DeploymentHistory(Base):
    __tablename__ = 'deployment_history'
    __table_args__ = (
        sa.Index('deployment_history_task_id_and_status', 'task_id', 'status'),
        sa.Index('deployment_history_task_name_status_idx',
                 'deployment_graph_task_name', 'status'),
        sa.UniqueConstraint(
            'task_id',
            'node_id',
            'deployment_graph_task_name',
            name='_task_id_node_id_deployment_graph_task_name_uc'),
    )

    id = sa.Column(sa.Integer, primary_key=True)
    task_id = sa.Column(sa.Integer,
                        sa.ForeignKey('tasks.id', ondelete='CASCADE'),
                        nullable=False)
    deployment_graph_task_name = sa.Column(sa.String, nullable=False)
    # String, because history need to be saved tasks for master and None nodes
    node_id = sa.Column(sa.String)
    time_start = sa.Column(sa.DateTime, nullable=True)
    time_end = sa.Column(sa.DateTime, nullable=True)
    status = sa.Column(sa.Enum(*consts.HISTORY_TASK_STATUSES,
                               name='history_task_statuses'),
                       nullable=False,
                       default=consts.HISTORY_TASK_STATUSES.pending)

    custom = sa.Column(MutableDict.as_mutable(JSON),
                       default={},
                       server_default='{}',
                       nullable=False)
    summary = deferred(
        sa.Column(MutableDict.as_mutable(JSON),
                  default={},
                  server_default='{}',
                  nullable=True))
Example #15
0
class OpenStackWorkloadStats(Base):
    __tablename__ = 'oswl_stats'
    __table_args__ = (UniqueConstraint('cluster_id', 'created_date',
                                       'resource_type'), )

    id = Column(Integer, primary_key=True)
    cluster_id = Column(Integer, nullable=False, index=True)

    created_date = Column(Date, nullable=False, index=True)
    updated_time = Column(Time, nullable=False)

    resource_type = Column(Enum(*consts.OSWL_RESOURCE_TYPES,
                                name='oswl_resource_type'),
                           nullable=False,
                           index=True)

    resource_data = Column(MutableDict.as_mutable(JSON), nullable=True)

    resource_checksum = Column(Text, nullable=False)
    is_sent = Column(Boolean, nullable=False, default=False, index=True)
    version_info = Column(MutableDict.as_mutable(postgresql.JSON),
                          nullable=True,
                          default={},
                          server_default='{}')
Example #16
0
class ActionLog(Base):
    __tablename__ = 'action_logs'

    id = Column(Integer, primary_key=True)
    actor_id = Column(String(64), nullable=True)
    action_group = Column(String(64), nullable=False)
    action_name = Column(String(64), nullable=False)
    action_type = Column(Enum(*consts.ACTION_TYPES, name='action_type'),
                         nullable=False)
    start_timestamp = Column(DateTime, nullable=False)
    end_timestamp = Column(DateTime, nullable=True)
    is_sent = Column(Boolean, default=False)
    additional_info = Column(MutableDict.as_mutable(JSON),
                             default={},
                             nullable=False)
    cluster_id = Column(Integer, nullable=True)
    task_uuid = Column(String(36), nullable=True)
Example #17
0
class NodeClusterPlugin(Base):

    __tablename__ = 'node_cluster_plugins'

    id = Column(Integer, primary_key=True)
    cluster_plugin_id = Column(Integer,
                               ForeignKey('cluster_plugins.id',
                                          ondelete='CASCADE'),
                               nullable=False)
    node_id = Column(Integer,
                     ForeignKey('nodes.id', ondelete='CASCADE'),
                     nullable=False)
    attributes = Column(MutableDict.as_mutable(JSON),
                        nullable=False,
                        server_default='{}')
    node = relationship("Node",
                        backref=backref("node_cluster_plugins",
                                        cascade="delete"))
Example #18
0
class NetworkGroup(Base):
    __tablename__ = 'network_groups'

    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False)
    # can be nullable only for fuelweb admin net
    release = Column(Integer, ForeignKey('releases.id', ondelete='CASCADE'))
    # can be nullable only for fuelweb admin net
    group_id = Column(Integer,
                      ForeignKey('nodegroups.id', ondelete='CASCADE'),
                      nullable=True)
    vlan_start = Column(Integer)
    cidr = Column(psql.CIDR)
    gateway = Column(psql.INET)
    ip_ranges = relationship("IPAddrRange",
                             backref="network_group",
                             cascade="all, delete, delete-orphan")
    nodes = relationship("Node",
                         secondary=IPAddr.__table__,
                         backref="networks",
                         passive_deletes=True)
    meta = Column(MutableDict.as_mutable(JSON), default={})
Example #19
0
class OpenstackConfig(Base):
    __tablename__ = 'openstack_configs'

    id = Column(Integer, primary_key=True)
    is_active = Column(Boolean, nullable=False, default=True)
    config_type = Column(Enum(*consts.OPENSTACK_CONFIG_TYPES,
                              name='openstack_config_types'),
                         nullable=False)

    # asaprykin: In case there will be global configuration
    # nullable should be set to 'True'
    cluster_id = Column(Integer,
                        ForeignKey('clusters.id', ondelete='CASCADE'),
                        nullable=False)
    node_id = Column(Integer,
                     ForeignKey('nodes.id', ondelete='SET NULL'),
                     nullable=True)
    node_role = Column(String(consts.ROLE_NAME_MAX_SIZE), nullable=True)

    created_at = Column(DateTime, nullable=False, default=datetime.now)
    configuration = Column(MutableDict.as_mutable(JSON),
                           nullable=False,
                           default={},
                           server_default='{}')
Example #20
0
class NodeBondInterface(Base):
    __tablename__ = 'node_bond_interfaces'
    id = Column(Integer, primary_key=True)
    node_id = Column(Integer,
                     ForeignKey('nodes.id', ondelete="CASCADE"),
                     nullable=False)
    name = Column(String(32), nullable=False)
    mac = Column(psql.MACADDR)
    assigned_networks_list = relationship(
        "NetworkGroup",
        secondary=NetworkBondAssignment.__table__,
        order_by="NetworkGroup.id")
    state = Column(String(25))
    interface_properties = Column(MutableDict.as_mutable(JSON),
                                  default={},
                                  nullable=False,
                                  server_default='{}')
    mode = Column(Enum(*consts.BOND_MODES, name='bond_mode'),
                  nullable=False,
                  default=consts.BOND_MODES.active_backup)
    bond_properties = Column(MutableDict.as_mutable(JSON),
                             default={},
                             nullable=False,
                             server_default='{}')
    slaves = relationship("NodeNICInterface", backref="bond")
    attributes = Column(MutableDict.as_mutable(JSON),
                        default={},
                        server_default='{}',
                        nullable=False)

    @property
    def max_speed(self):
        return None

    @property
    def current_speed(self):
        return None

    @property
    def type(self):
        return consts.NETWORK_INTERFACE_TYPES.bond

    @property
    def assigned_networks(self):
        return [{
            "id": n.id,
            "name": n.name
        } for n in self.assigned_networks_list]

    @assigned_networks.setter
    def assigned_networks(self, value):
        self.assigned_networks_list = value

    @property
    def offloading_modes(self):
        tmp = None
        intersection_dict = {}
        for interface in self.slaves:
            modes = interface.offloading_modes
            if tmp is None:
                tmp = modes
                intersection_dict = \
                    interface.offloading_modes_as_flat_dict(tmp)
                continue
            intersection_dict = self._intersect_offloading_dicts(
                intersection_dict,
                interface.offloading_modes_as_flat_dict(modes))

        return self._apply_intersection(tmp, intersection_dict)

    @offloading_modes.setter
    def offloading_modes(self, new_modes):
        new_modes_dict = \
            NodeNICInterface.offloading_modes_as_flat_dict(new_modes)
        for interface in self.slaves:
            self._update_modes(interface.offloading_modes, new_modes_dict)
            interface.offloading_modes.changed()

    def _update_modes(self, modes, update_dict):
        for mode in modes:
            if mode['name'] in update_dict:
                mode['state'] = update_dict[mode['name']]
            if mode['sub']:
                self._update_modes(mode['sub'], update_dict)

    def _intersect_offloading_dicts(self, dict1, dict2):
        result = dict()
        for mode in dict1:
            if mode in dict2:
                result[mode] = dict1[mode] and dict2[mode]
        return result

    def _apply_intersection(self, modes, intersection_dict):
        result = list()
        if modes is None:
            return result
        for mode in copy.deepcopy(modes):
            if mode["name"] not in intersection_dict:
                continue
            mode["state"] = intersection_dict[mode["name"]]
            if mode["sub"]:
                mode["sub"] = \
                    self._apply_intersection(mode["sub"], intersection_dict)
            result.append(mode)
        return result
Example #21
0
 def setUp(self):
     self.standard = {'1': 1}
     self.mutable_dict = MutableDict()
     self.mutable_dict.update(self.standard)
Example #22
0
 def test_coerce_mutable_dict(self, m_coerce):
     dct = MutableDict()
     self.assertIsInstance(self.mutable_dict.coerce('key', dct),
                           MutableDict)
     self.assertFalse(m_coerce.called)
Example #23
0
class Cluster(Base):
    __tablename__ = 'clusters'
    id = Column(Integer, primary_key=True)
    #集群模式
    mode = Column(
        Enum(*consts.CLUSTER_MODES, name='cluster_mode'),
        nullable=False,
        default=consts.CLUSTER_MODES.ha_compact
    )
    status = Column(
        Enum(*consts.CLUSTER_STATUSES, name='cluster_status'),
        nullable=False,
        default=consts.CLUSTER_STATUSES.new
    )
    net_provider = Column(
        Enum(*consts.CLUSTER_NET_PROVIDERS, name='net_provider'),
        nullable=False,
        default=consts.CLUSTER_NET_PROVIDERS.neutron
    )
    network_config = relationship("NetworkingConfig",
                                  backref=backref("cluster"),
                                  cascade="all,delete",
                                  uselist=False)
    ui_settings = Column(
        MutableDict.as_mutable(JSON),
        nullable=False,
        server_default=jsonutils.dumps({
            "view_mode": "standard",
            "filter": {},
            "sort": [{"roles": "asc"}],
            "filter_by_labels": {},
            "sort_by_labels": [],
            "search": ""
        }),
    )
    name = Column(UnicodeText, unique=True, nullable=False)
    release_id = Column(Integer, ForeignKey('releases.id'), nullable=False)
    nodes = relationship(
        "Node", backref="cluster", cascade="delete", order_by='Node.id')
    tasks = relationship("Task", backref="cluster")
    plugin_links = relationship(
        "ClusterPluginLink", backref="cluster", cascade="delete")
    attributes = relationship("Attributes", uselist=False,
                              backref="cluster", cascade="delete")
    changes_list = relationship("ClusterChanges", backref="cluster",
                                cascade="delete")
    # We must keep all notifications even if cluster is removed.
    # It is because we want user to be able to see
    # the notification history so that is why we don't use
    # cascade="delete" in this relationship
    # During cluster deletion sqlalchemy engine will set null
    # into cluster foreign key column of notification entity
    notifications = relationship("Notification", backref="cluster")
    node_groups = relationship(
        "NodeGroup",
        backref="cluster",
        cascade="delete"
    )
    replaced_deployment_info = Column(
        MutableDict.as_mutable(JSON), default={}
    )
    replaced_provisioning_info = Column(
        MutableDict.as_mutable(JSON), default={})
    is_customized = Column(Boolean, default=False)
    fuel_version = Column(Text, nullable=False)
    components = Column(
        MutableList.as_mutable(JSON),
        default=[],
        server_default='[]',
        nullable=False)
    extensions = Column(psql.ARRAY(String(consts.EXTENSION_NAME_MAX_SIZE)),
                        default=[], nullable=False, server_default='{}')
    volumes_metadata = Column(MutableDict.as_mutable(JSON),
                              default={},
                              server_default='{}')
    roles_metadata = Column(MutableDict.as_mutable(JSON),
                            default={},
                            server_default='{}')
    tags_metadata = Column(MutableDict.as_mutable(JSON),
                           server_default='{}',
                           nullable=False)

    @property
    def changes(self):
        return [
            {"name": i.name, "node_id": i.node_id}
            for i in self.changes_list
        ]

    @changes.setter
    def changes(self, value):
        self.changes_list = value

    @property
    def is_ha_mode(self):
        return self.mode in ('ha_full', 'ha_compact')

    @property
    def full_name(self):
        return '%s (id=%s, mode=%s)' % (self.name, self.id, self.mode)

    @property
    def is_locked(self):
        allowed_status = (
            consts.CLUSTER_STATUSES.error,
            consts.CLUSTER_STATUSES.new,
            consts.CLUSTER_STATUSES.operational,
            consts.CLUSTER_STATUSES.stopped,
            consts.CLUSTER_STATUSES.partially_deployed
        )
        return self.status not in allowed_status

    @property
    def network_groups(self):
        net_list = []
        for ng in self.node_groups:
            net_list.extend(ng.networks)
        return net_list
Example #24
0
 def setUp(self):
     super(TestMutableDictBase, self).setUp()
     self.standard = {'1': 1}
     self.mutable_obj = MutableDict()
     self.mutable_obj.update(self.standard)
Example #25
0
class DeploymentGraphTask(Base):
    __tablename__ = 'deployment_graph_tasks'
    __table_args__ = (
        sa.UniqueConstraint(
            'deployment_graph_id',
            'task_name',
            name='_task_name_deployment_graph_id_uc'),
    )
    id = sa.Column(
        sa.Integer,
        primary_key=True)
    deployment_graph_id = sa.Column(
        sa.Integer,
        sa.ForeignKey('deployment_graphs.id', ondelete='CASCADE'),
        nullable=False)
    deployment_graph = sa.orm.relationship(
        'DeploymentGraph',
        backref=sa.orm.backref("tasks", cascade="all, delete-orphan"))

    # not task_id because it could be perceived as fk
    # and not id because it is not unique inside table
    task_name = sa.Column(
        sa.String(255),
        index=True,
        nullable=False)
    version = sa.Column(
        sa.String(255),
        nullable=False,
        server_default='1.0.0',
        default='1.0.0')
    # this field may contain string or dict
    condition = sa.Column(
        JSON(),
        nullable=True)
    type = sa.Column(
        sa.Enum(
            *consts.ORCHESTRATOR_TASK_TYPES,
            name='deployment_graph_tasks_type'),
        nullable=False)
    groups = sa.Column(
        sa.dialects.postgresql.ARRAY(sa.String(255)),
        default=[],
        server_default='{}',
        nullable=False)
    tasks = sa.Column(
        sa.dialects.postgresql.ARRAY(sa.String(255)),
        default=[],
        server_default='{}',
        nullable=False)
    roles = sa.Column(    # node roles
        sa.dialects.postgresql.ARRAY(sa.String(255)),
        default=[],
        server_default='{}',
        nullable=False)
    # list of Nailgun events on which this task should be re-executed
    reexecute_on = sa.Column(
        sa.dialects.postgresql.ARRAY(sa.String(255)),
        default=[],
        server_default='{}',
        nullable=False)
    refresh_on = sa.Column(    # new in 8.0
        sa.dialects.postgresql.ARRAY(sa.String(255)),
        default=[],
        server_default='{}',
        nullable=False)
    required_for = sa.Column(
        sa.dialects.postgresql.ARRAY(sa.String(255)),
        default=[],
        server_default='{}',
        nullable=False)
    requires = sa.Column(
        sa.dialects.postgresql.ARRAY(sa.String(255)),
        default=[],
        server_default='{}',
        nullable=False)
    # cross-depended-by with hypen is deprecated notation
    cross_depended_by = sa.Column(
        MutableList.as_mutable(JSON),
        default=[],
        server_default='[]')
    # cross-depends with hypen is deprecated notation
    cross_depends = sa.Column(
        MutableList.as_mutable(JSON),
        default=[],
        server_default='[]')
    parameters = sa.Column(
        MutableDict.as_mutable(JSON),
        default={},
        server_default='{}')
    # custom field for all fields that does not fit into the schema
    _custom = sa.Column(
        MutableDict.as_mutable(JSON),
        default={},
        server_default='{}')
Example #26
0
class Attributes(Base):
    __tablename__ = 'attributes'
    id = Column(Integer, primary_key=True)
    cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete='CASCADE'))
    editable = Column(MutableDict.as_mutable(JSON))
    generated = Column(MutableDict.as_mutable(JSON))
Example #27
0
 def test_initialize(self):
     with mock.patch('sqlalchemy.ext.mutable.Mutable.changed') as m_changed:
         MutableDict(key1='value1', key2='value2')
         self._assert_object_not_changed(m_changed)
Example #28
0
class Node(Base):
    __tablename__ = 'nodes'
    __table_args__ = (UniqueConstraint('cluster_id',
                                       'hostname',
                                       name='_hostname_cluster_uc'), )
    id = Column(Integer, primary_key=True)
    uuid = Column(String(36),
                  nullable=False,
                  default=lambda: str(uuid.uuid4()),
                  unique=True)
    cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete='CASCADE'))
    group_id = Column(Integer,
                      ForeignKey('nodegroups.id', ondelete='SET NULL'),
                      nullable=True)
    name = Column(Unicode(100))
    status = Column(Enum(*consts.NODE_STATUSES, name='node_status'),
                    nullable=False,
                    default=consts.NODE_STATUSES.discover)
    meta = Column(MutableDict.as_mutable(JSON), default={})
    mac = Column(psql.MACADDR, nullable=False, unique=True)
    ip = Column(psql.INET)
    hostname = Column(String(255),
                      nullable=False,
                      default="",
                      server_default="")
    manufacturer = Column(Unicode(50))
    platform_name = Column(String(150))
    kernel_params = Column(Text)
    progress = Column(Integer, default=0)
    os_platform = Column(String(150))
    pending_addition = Column(Boolean, default=False)
    pending_deletion = Column(Boolean, default=False)
    changes = relationship("ClusterChanges", backref="node")
    error_type = Column(String(100))
    error_msg = Column(Text)
    timestamp = Column(DateTime, nullable=False)
    online = Column(Boolean, default=True)
    labels = Column(MutableDict.as_mutable(JSON),
                    nullable=False,
                    server_default='{}')
    tags = relationship('NodeTag', cascade='delete, delete-orphan')
    roles = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)),
                   default=[],
                   nullable=False,
                   server_default='{}')
    pending_roles = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)),
                           default=[],
                           nullable=False,
                           server_default='{}')
    primary_roles = Column(psql.ARRAY(String(consts.ROLE_NAME_MAX_SIZE)),
                           default=[],
                           nullable=False,
                           server_default='{}')
    nic_interfaces = relationship("NodeNICInterface",
                                  backref="node",
                                  cascade="all, delete-orphan",
                                  order_by="NodeNICInterface.name")
    bond_interfaces = relationship("NodeBondInterface",
                                   backref="node",
                                   cascade="all, delete-orphan",
                                   order_by="NodeBondInterface.name")
    # hash function from raw node agent request data - for caching purposes
    agent_checksum = Column(String(40), nullable=True)

    ip_addrs = relationship("IPAddr", viewonly=True)
    replaced_deployment_info = Column(MutableList.as_mutable(JSON), default=[])
    replaced_provisioning_info = Column(MutableDict.as_mutable(JSON),
                                        default={})
    network_template = Column(MutableDict.as_mutable(JSON),
                              default=None,
                              server_default=None,
                              nullable=True)
    extensions = Column(psql.ARRAY(String(consts.EXTENSION_NAME_MAX_SIZE)),
                        default=[],
                        nullable=False,
                        server_default='{}')
    vms_conf = Column(MutableList.as_mutable(JSON),
                      default=[],
                      server_default='[]',
                      nullable=False)
    attributes = Column(MutableDict.as_mutable(JSON),
                        default={},
                        server_default='{}',
                        nullable=False)

    @property
    def interfaces(self):
        return self.nic_interfaces + self.bond_interfaces

    @property
    def uid(self):
        return str(self.id)

    @property
    def offline(self):
        return not self.online

    @property
    def network_data(self):
        # TODO(enchantner): move to object
        from nailgun.extensions.network_manager.manager import NetworkManager
        return NetworkManager.get_node_networks(self)

    @property
    def needs_reprovision(self):
        return self.status == 'error' and self.error_type == 'provision' and \
            not self.pending_deletion

    @property
    def needs_redeploy(self):
        return (self.status in [
            consts.NODE_STATUSES.error, consts.NODE_STATUSES.provisioned,
            consts.NODE_STATUSES.stopped
        ] or len(self.pending_roles)) and not self.pending_deletion

    @property
    def needs_redeletion(self):
        return self.status == 'error' and self.error_type == 'deletion'

    @property
    def human_readable_name(self):
        return self.name or self.mac

    @property
    def full_name(self):
        return u'%s (id=%s, mac=%s)' % (self.name, self.id, self.mac)

    @property
    def tag_names(self):
        return (t.tag.tag for t in self.tags)

    @property
    def all_roles(self):
        """Returns all roles, self.roles and self.pending_roles."""
        return set(self.pending_roles + self.roles)

    def _check_interface_has_required_params(self, iface):
        return bool(iface.get('name') and iface.get('mac'))

    def _clean_iface(self, iface):
        # cleaning up unnecessary fields - set to None if bad
        for param in ["max_speed", "current_speed"]:
            val = iface.get(param)
            if not (isinstance(val, int) and val >= 0):
                val = None
            iface[param] = val
        return iface

    def update_meta(self, data):
        # helper for basic checking meta before updation
        result = []
        if "interfaces" in data:
            for iface in data["interfaces"]:
                if not self._check_interface_has_required_params(iface):
                    logger.warning("Invalid interface data: {0}. "
                                   "Interfaces are not updated.".format(iface))
                    data["interfaces"] = self.meta.get("interfaces")
                    self.meta = data
                    return
                result.append(self._clean_iface(iface))

        data["interfaces"] = result
        self.meta = data

    def create_meta(self, data):
        # helper for basic checking meta before creation
        result = []
        if "interfaces" in data:
            for iface in data["interfaces"]:
                if not self._check_interface_has_required_params(iface):
                    logger.warning("Invalid interface data: {0}. "
                                   "Skipping interface.".format(iface))
                    continue
                result.append(self._clean_iface(iface))

        data["interfaces"] = result
        self.meta = data
Example #29
0
 def setUp(self):
     self.standard = {'1': 1}
     self.mutable_dict = MutableDict()
     self.mutable_dict.update(self.standard)
Example #30
0
class Release(Base):
    __tablename__ = 'releases'
    __table_args__ = (UniqueConstraint('name', 'version'), )
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(100), nullable=False)
    version = Column(String(30), nullable=False)
    description = Column(Unicode)
    operating_system = Column(String(50), nullable=False)
    state = Column(Enum(*consts.RELEASE_STATES, name='release_state'),
                   nullable=False,
                   default=consts.RELEASE_STATES.unavailable)
    networks_metadata = Column(MutableDict.as_mutable(JSON), default={})
    attributes_metadata = Column(MutableDict.as_mutable(JSON), default={})
    volumes_metadata = Column(MutableDict.as_mutable(JSON), default={})
    modes_metadata = Column(MutableDict.as_mutable(JSON), default={})
    roles_metadata = Column(MutableDict.as_mutable(JSON), default={})
    tags_metadata = Column(MutableDict.as_mutable(JSON), default={})
    network_roles_metadata = Column(MutableList.as_mutable(JSON),
                                    default=[],
                                    server_default='[]')
    vmware_attributes_metadata = Column(MutableDict.as_mutable(JSON),
                                        default={})
    components_metadata = Column(MutableList.as_mutable(JSON),
                                 default=[],
                                 server_default='[]')
    required_component_types = Column(MutableList.as_mutable(JSON),
                                      default=[],
                                      server_default='[]',
                                      nullable=False)
    modes = Column(MutableList.as_mutable(JSON), default=[])
    clusters = relationship("Cluster",
                            primaryjoin="Release.id==Cluster.release_id",
                            backref="release",
                            cascade="all,delete")
    extensions = Column(psql.ARRAY(String(consts.EXTENSION_NAME_MAX_SIZE)),
                        default=[],
                        nullable=False,
                        server_default='{}')
    node_attributes = Column(MutableDict.as_mutable(JSON),
                             default={},
                             server_default='{}',
                             nullable=False)
    nic_attributes = Column(MutableDict.as_mutable(JSON),
                            default={},
                            server_default='{}',
                            nullable=False)
    bond_attributes = Column(MutableDict.as_mutable(JSON),
                             default={},
                             server_default='{}',
                             nullable=False)

    # TODO(enchantner): get rid of properties

    @property
    def openstack_version(self):
        return self.version.split('-')[0]

    @property
    def environment_version(self):
        """Returns environment version based on release version.

        A release version consists of 'OSt' and 'MOS' versions:
            '2014.1.1-5.0.2'

        so we need to extract 'MOS' version and returns it as result.

        :returns: an environment version
        """
        # unfortunately, Fuel 5.0 didn't have an env version in release_version
        # so we need to handle that special case
        if self.version == '2014.1':
            version = '5.0'
        else:
            try:
                version = self.version.split('-')[1]
            except IndexError:
                version = ''

        return version

    @property
    def os_weight(self):
        try:
            weight = consts.RELEASE_OS[::-1].index(self.operating_system)
        except ValueError:
            weight = -1

        return weight

    def __cmp__(self, other):
        """Allows to compare two releases

        :other: an instance of nailgun.db.sqlalchemy.models.release.Release
        """
        if self.environment_version < other.environment_version:
            return -1
        if self.environment_version > other.environment_version:
            return 1

        if self.openstack_version < other.openstack_version:
            return -1
        if self.openstack_version > other.openstack_version:
            return 1

        if self.os_weight == other.os_weight == -1:
            if self.operating_system > other.operating_system:
                return -1
            if self.operating_system < other.operating_system:
                return 1
        else:
            if self.os_weight < other.os_weight:
                return -1
            if self.os_weight > other.os_weight:
                return 1

        return 0
Example #31
0
 def setUp(self):
     super(TestMutableDictCoerce, self).setUp()
     self.mutable_dict = MutableDict()
Example #32
0
class CapacityLog(Base):
    __tablename__ = 'capacity_log'

    id = Column(Integer, primary_key=True)
    report = Column(MutableDict.as_mutable(JSON))
    datetime = Column(DateTime, default=lambda: datetime.now())
Example #33
0
 def setUp(self):
     super(TestMutableDictBase, self).setUp()
     self.standard = {'1': 1}
     self.mutable_obj = MutableDict()
     self.mutable_obj.update(self.standard)
Example #34
0
class NodeNICInterface(Base):
    __tablename__ = 'node_nic_interfaces'
    id = Column(Integer, primary_key=True)
    node_id = Column(Integer,
                     ForeignKey('nodes.id', ondelete="CASCADE"),
                     nullable=False)
    name = Column(String(128), nullable=False)
    mac = Column(psql.MACADDR, nullable=False)
    max_speed = Column(Integer)
    current_speed = Column(Integer)
    assigned_networks_list = relationship(
        "NetworkGroup",
        secondary=NetworkNICAssignment.__table__,
        order_by="NetworkGroup.id")
    ip_addr = Column(psql.INET)
    netmask = Column(psql.INET)
    state = Column(String(25))
    interface_properties = Column(MutableDict.as_mutable(JSON),
                                  default={},
                                  nullable=False,
                                  server_default='{}')
    parent_id = Column(
        Integer, ForeignKey('node_bond_interfaces.id', ondelete='SET NULL'))
    driver = Column(Text)
    bus_info = Column(Text)
    pxe = Column(Boolean, default=False, nullable=False)

    offloading_modes = Column(MutableList.as_mutable(JSON),
                              default=[],
                              nullable=False,
                              server_default='[]')
    attributes = Column(MutableDict.as_mutable(JSON),
                        default={},
                        server_default='{}',
                        nullable=False)
    meta = Column(MutableDict.as_mutable(JSON),
                  default={},
                  server_default='{}',
                  nullable=False)

    @property
    def type(self):
        return consts.NETWORK_INTERFACE_TYPES.ether

    @property
    def assigned_networks(self):
        return [{
            "id": n.id,
            "name": n.name
        } for n in self.assigned_networks_list]

    @assigned_networks.setter
    def assigned_networks(self, value):
        self.assigned_networks_list = value

    # TODO(fzhadaev): move to object
    @classmethod
    def offloading_modes_as_flat_dict(cls, modes):
        """Represents multilevel structure of offloading modes as flat dict

        This is done to ease merging
        :param modes: list of offloading modes
        :return: flat dictionary {mode['name']: mode['state']}
        """
        result = dict()
        if modes is None:
            return result
        for mode in modes:
            result[mode["name"]] = mode["state"]
            if mode["sub"]:
                result.update(cls.offloading_modes_as_flat_dict(mode["sub"]))
        return result
Example #35
0
class Task(Base):
    __tablename__ = 'tasks'
    __table_args__ = (Index('cluster_name_idx', 'cluster_id', 'name'), )

    id = Column(Integer, primary_key=True)
    cluster_id = Column(Integer, ForeignKey('clusters.id', ondelete='CASCADE'))
    uuid = Column(String(36),
                  nullable=False,
                  default=lambda: str(uuid.uuid4()))
    name = Column(Enum(*consts.TASK_NAMES, name='task_name'),
                  nullable=False,
                  default='super')
    message = Column(Text)
    status = Column(Enum(*consts.TASK_STATUSES, name='task_status'),
                    nullable=False,
                    default='running')
    progress = Column(Integer, default=0)
    cache = deferred(Column(MutableDict.as_mutable(JSON), default={}))
    # By design 'result' value accept dict and list types
    # depends on task type. Don't do this field MutableDict.
    result = Column(JSON, default={})
    parent_id = Column(Integer, ForeignKey('tasks.id', ondelete='CASCADE'))
    subtasks = relationship("Task",
                            backref=backref('parent', remote_side=[id]),
                            cascade="all,delete")
    notifications = relationship("Notification",
                                 backref=backref('task', remote_side=[id]))
    # Task weight is used to calculate supertask progress
    # sum([t.progress * t.weight for t in supertask.subtasks]) /
    # sum([t.weight for t in supertask.subtasks])
    weight = Column(Float, default=1.0)
    deleted_at = Column(DateTime)

    deployment_info = deferred(
        Column(MutableDict.as_mutable(JSON), nullable=True))
    cluster_settings = deferred(
        Column(MutableDict.as_mutable(JSON), nullable=True))
    network_settings = deferred(
        Column(MutableDict.as_mutable(JSON), nullable=True))

    deployment_history = relationship("DeploymentHistory",
                                      backref="task",
                                      cascade="all,delete")

    def __repr__(self):
        return "<Task '{0}' {1} ({2}) {3}>".format(self.name, self.uuid,
                                                   self.cluster_id,
                                                   self.status)

    def create_subtask(self, name, **kwargs):
        if not name:
            raise ValueError("Subtask name not specified")

        task = Task(name=name, cluster=self.cluster, **kwargs)
        self.subtasks.append(task)
        db().flush()
        return task

    def is_completed(self):
        return self.status == consts.TASK_STATUSES.error or \
            self.status == consts.TASK_STATUSES.ready