Example #1
0
class NeutronConfig(NetworkingConfig):
    __tablename__ = 'neutron_config'
    __mapper_args__ = {
        'polymorphic_identity': 'neutron_config',
    }

    id = Column(Integer, ForeignKey('networking_configs.id'), primary_key=True)

    vlan_range = Column(MutableList.as_mutable(JSON), default=[])
    gre_id_range = Column(MutableList.as_mutable(JSON), default=[])
    base_mac = Column(psql.MACADDR, nullable=False)
    internal_cidr = Column(psql.CIDR)
    internal_gateway = Column(psql.INET)
    baremetal_gateway = Column(psql.INET)
    baremetal_range = Column(MutableList.as_mutable(JSON), default=[])

    # Neutron L3 names for default internal / floating networks
    # which were previously knows as net04 and net04_ext.
    internal_name = Column(String(50), nullable=False)
    floating_name = Column(String(50), nullable=False)

    segmentation_type = Column(
        Enum(*consts.NEUTRON_SEGMENT_TYPES,
             name='segmentation_type'),
        nullable=False,
        default=consts.NEUTRON_SEGMENT_TYPES.vlan
    )
    net_l23_provider = Column(
        Enum(*consts.NEUTRON_L23_PROVIDERS, name='net_l23_provider'),
        nullable=False,
        default=consts.NEUTRON_L23_PROVIDERS.ovs
    )
Example #2
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 #3
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='[]')
    deployment_tasks = Column(MutableList.as_mutable(JSON),
                              server_default='[]',
                              nullable=False)
    # 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.
    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 #4
0
class NodeAttributes(Base):
    __tablename__ = 'node_attributes'
    id = Column(Integer, primary_key=True)
    node_id = Column(Integer, ForeignKey('nodes.id', ondelete='CASCADE'))
    interfaces = Column(MutableDict.as_mutable(JSON), default={})
    vms_conf = Column(MutableList.as_mutable(JSON),
                      default=[], server_default='[]')
Example #5
0
    def test_copy_mutable_list(self):
        mlist = MutableList([{"a": 1, "b": 2}])
        shallow_copy = copy.copy(mlist)
        self.assertEqual(mlist, shallow_copy)
        self.assertIs(mlist[0], shallow_copy[0])

        deep_copy = copy.deepcopy(mlist)
        self.assertEqual(mlist, deep_copy)
        self.assertIsNot(mlist[0], deep_copy[0])
Example #6
0
    def test_deep_copy(self, m_changed):
        lst = MutableList(('element1', 'element2'))
        self.mutable_obj.insert(0, lst)

        m_changed.reset_mock()
        clone = deepcopy(self.mutable_obj)
        self.assertEqual(0, m_changed.call_count)

        lst[0] = 'new_element'
        self.assertEqual(clone[0][0], 'element1')
        self.assertEqual(self.mutable_obj[0][0], 'new_element')
Example #7
0
class TestMutableListCoerce(BaseUnitTest):
    def setUp(self):
        self.mutable_list = MutableList()

    def test_coerce_mutable_list(self, m_coerce):
        lst = MutableList()
        self.assertIsInstance(
            self.mutable_list.coerce('key', lst), MutableList)
        self.assertFalse(m_coerce.called)

    def test_coerce_list(self, m_coerce):
        lst = list()
        self.assertIsInstance(
            self.mutable_list.coerce('key', lst), MutableList)
        self.assertFalse(m_coerce.called)

    def test_coerce_not_acceptable_object(self, m_coerce):
        m_coerce.return_value = None
        obj = dict()
        self.mutable_list.coerce('key', obj)
        m_coerce.assert_called_once_with('key', obj)
class DeploymentSequence(Base):
    __tablename__ = 'deployment_sequences'
    __table_args__ = (sa.UniqueConstraint('release_id',
                                          'name',
                                          name='_name_uc'), )
    id = sa.Column(sa.Integer, primary_key=True)
    release_id = sa.Column(sa.Integer,
                           sa.ForeignKey('releases.id'),
                           nullable=False)
    name = sa.Column(sa.String(255), nullable=False)
    # contains graphs to execute
    graphs = sa.Column(MutableList.as_mutable(JSON), nullable=False)
Example #9
0
class TestMutableListCoerce(BaseUnitTest):
    def setUp(self):
        self.mutable_list = MutableList()

    def test_coerce_mutable_list(self, m_coerce):
        lst = MutableList()
        self.assertIsInstance(self.mutable_list.coerce('key', lst),
                              MutableList)
        self.assertFalse(m_coerce.called)

    def test_coerce_list(self, m_coerce):
        lst = list()
        self.assertIsInstance(self.mutable_list.coerce('key', lst),
                              MutableList)
        self.assertFalse(m_coerce.called)

    def test_coerce_not_acceptable_object(self, m_coerce):
        m_coerce.return_value = None
        obj = dict()
        self.mutable_list.coerce('key', obj)
        m_coerce.assert_called_once_with('key', obj)
Example #10
0
    def test_deep_copy(self, m_changed):
        lst = MutableList(('element1', 'element2'))
        self.mutable_list.insert(0, lst)

        m_changed.reset_mock()
        clone = deepcopy(self.mutable_list)
        # changed should calls two times
        # - root cloned list (clone)
        # - mutable list element in root list (cloned lst)
        self.assertEqual(m_changed.call_count, 2)

        lst[0] = 'new_element'
        self.assertEqual(clone[0][0], 'element1')
        self.assertEqual(self.mutable_list[0][0], 'new_element')
Example #11
0
 def setUp(self):
     self.mutable_list = MutableList()
Example #12
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 #13
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 #14
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 #15
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'))
    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='[]')

    @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 #16
0
 def setUp(self):
     self.mutable_list = MutableList()
Example #17
0
 def setUp(self):
     super(TestMutableListBase, self).setUp()
     self.standard = ['element1', 'element2']
     self.mutable_obj = MutableList()
     self.mutable_obj.extend(self.standard)
Example #18
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 #19
0
 def test_initialize(self):
     with mock.patch('sqlalchemy.ext.mutable.Mutable.changed') as m_changed:
         MutableList([1, 2, 3])
         self._assert_object_not_changed(m_changed)
Example #20
0
 def test_coerce_mutable_list(self, m_coerce):
     lst = MutableList()
     self.assertIsInstance(self.mutable_list.coerce('key', lst),
                           MutableList)
     self.assertFalse(m_coerce.called)
Example #21
0
 def setUp(self):
     super(TestMutableListBase, self).setUp()
     self.standard = ['element1', 'element2']
     self.mutable_obj = MutableList()
     self.mutable_obj.extend(self.standard)
Example #22
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",
                            order_by='Task.id')
    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)
    dry_run = Column(Boolean(),
                     nullable=False,
                     default=False,
                     server_default='false')
    graph_type = Column(String(255))
    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))

    tasks_snapshot = deferred(
        Column(MutableList.as_mutable(JSON), nullable=True))

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

    time_start = Column(TIMESTAMP(), nullable=True)
    time_end = Column(TIMESTAMP(), nullable=True)

    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
Example #23
0
 def test_pop_default_from_empty_list(self):
     self.standard = []
     self.mutable_obj = MutableList()
     self._check_failure(IndexError, 'pop')