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(JSON, default=[]) gre_id_range = Column(JSON, default=[]) base_mac = Column(LowercaseString(17), nullable=False) internal_cidr = Column(String(25)) internal_gateway = Column(String(25)) external_gateway = Column(String(25)) l3_enabled = Column(Boolean, default=True) basic_net = Column(Text) external_config = Column(Text) 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 )
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(LowercaseString(17), 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(String(25)) netmask = Column(String(25)) state = Column(String(25)) parent_id = Column(Integer, ForeignKey('node_bond_interfaces.id')) @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
def upgrade(): ### commands auto generated by Alembic - please adjust! ### op.drop_table('global_parameters') op.alter_column('network_groups', 'netmask', existing_type=sa.VARCHAR(length=25), nullable=True) op.drop_table('plugins') op.drop_table('allowed_networks') op.add_column('network_groups', sa.Column('meta', JSON(), nullable=True)) op.add_column('node_nic_interfaces', sa.Column('parent_id', sa.Integer(), nullable=True)) op.rename_table('net_assignments', 'net_nic_assignments') op.create_table( 'node_bond_interfaces', sa.Column('id', sa.Integer(), nullable=False), sa.Column('node_id', sa.Integer(), nullable=False), sa.Column('name', sa.String(length=32), nullable=False), sa.Column('mac', LowercaseString(length=17), nullable=True), sa.Column('state', sa.String(length=25), nullable=True), sa.Column('flags', JSON(), nullable=True), sa.Column('mode', sa.Enum('active-backup', 'balance-slb', 'lacp-balance-tcp', name='bond_mode'), nullable=False), sa.ForeignKeyConstraint(['node_id'], ['nodes.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id')) op.create_table( 'net_bond_assignments', sa.Column('id', sa.Integer(), nullable=False), sa.Column('network_id', sa.Integer(), nullable=False), sa.Column('bond_id', sa.Integer(), nullable=False), sa.ForeignKeyConstraint(['bond_id'], ['node_bond_interfaces.id'], ondelete='CASCADE'), sa.ForeignKeyConstraint(['network_id'], ['network_groups.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id')) # CLUSTER STATUS ENUM UPGRADE upgrade_enum( "clusters", # table "status", # column "cluster_status", # ENUM name old_cluster_status_options, # old options new_cluster_status_options # new options ) # TASK NAME ENUM UPGRADE upgrade_enum( "tasks", # table "name", # column "task_name", # ENUM name old_task_names_options, # old options new_task_names_options # new options )
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(LowercaseString(17)) assigned_networks_list = relationship( "NetworkGroup", secondary=NetworkBondAssignment.__table__, order_by="NetworkGroup.id") state = Column(String(25)) interface_properties = Column(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(JSON, default={}, nullable=False, server_default='{}') slaves = relationship("NodeNICInterface", backref="bond") @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
def upgrade(): op.create_table('red_hat_accounts', sa.Column('id', sa.Integer(), nullable=False), sa.Column( 'username', sa.String(length=100), nullable=False), sa.Column( 'password', sa.String(length=100), nullable=False), sa.Column('license_type', sa.Enum( 'rhsm', 'rhn', name='license_type'), nullable=False), sa.Column( 'satellite', sa.String(length=250), nullable=True), sa.Column( 'activation_key', sa.String(length=300), nullable=True), sa.PrimaryKeyConstraint('id') ) op.create_table('capacity_log', sa.Column('id', sa.Integer(), nullable=False), sa.Column('report', JSON(), nullable=True), sa.Column('datetime', sa.DateTime(), nullable=True), sa.PrimaryKeyConstraint('id') ) op.create_table('releases', sa.Column('id', sa.Integer(), nullable=False), sa.Column('name', sa.Unicode(length=100), nullable=False), sa.Column('version', sa.String(length=30), nullable=False), sa.Column('description', sa.Unicode(), nullable=True), sa.Column( 'operating_system', sa.String(length=50), nullable=False), sa.Column('state', sa.Enum('not_available', 'downloading', 'error', 'available', name='release_state'), nullable=False), sa.Column('networks_metadata', JSON(), nullable=True), sa.Column('attributes_metadata', JSON(), nullable=True), sa.Column('volumes_metadata', JSON(), nullable=True), sa.Column('modes_metadata', JSON(), nullable=True), sa.Column('roles_metadata', JSON(), nullable=True), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('name', 'version') ) op.create_table('clusters', sa.Column('id', sa.Integer(), nullable=False), sa.Column('mode', sa.Enum( 'multinode', 'ha_full', 'ha_compact', name='cluster_mode'), nullable=False), sa.Column('status', sa.Enum('new', 'deployment', 'stopped', 'operational', 'error', 'remove', name='cluster_status'), nullable=False), sa.Column('net_provider', sa.Enum( 'nova_network', 'neutron', name='net_provider'), nullable=False), sa.Column('grouping', sa.Enum( 'roles', 'hardware', 'both', name='cluster_grouping'), nullable=False), sa.Column('name', sa.Unicode(length=50), nullable=False), sa.Column('release_id', sa.Integer(), nullable=False), sa.Column( 'replaced_deployment_info', JSON(), nullable=True), sa.Column( 'replaced_provisioning_info', JSON(), nullable=True), sa.Column('is_customized', sa.Boolean(), nullable=True), sa.Column( 'fuel_version', sa.Text, nullable=False), sa.ForeignKeyConstraint(['release_id'], ['releases.id'], ), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('name') ) op.create_table('release_orchestrator_data', sa.Column('id', sa.Integer(), nullable=False), sa.Column('release_id', sa.Integer(), nullable=False), sa.Column('repo_metadata', JSON(), nullable=False), sa.Column( 'puppet_manifests_source', sa.Text(), nullable=False), sa.Column( 'puppet_modules_source', sa.Text(), nullable=False), sa.ForeignKeyConstraint(['release_id'], ['releases.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('roles', sa.Column('id', sa.Integer(), nullable=False), sa.Column('release_id', sa.Integer(), nullable=False), sa.Column('name', sa.String(length=50), nullable=False), sa.ForeignKeyConstraint( ['release_id'], ['releases.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('name', 'release_id') ) op.create_table('nodes', sa.Column('id', sa.Integer(), nullable=False), sa.Column('uuid', sa.String(length=36), nullable=False), sa.Column('cluster_id', sa.Integer(), nullable=True), sa.Column('name', sa.Unicode(length=100), nullable=True), sa.Column('status', sa.Enum('ready', 'discover', 'provisioning', 'provisioned', 'deploying', 'error', name='node_status'), nullable=False), sa.Column('meta', JSON(), nullable=True), sa.Column('mac', LowercaseString(), nullable=False), sa.Column('ip', sa.String(length=15), nullable=True), sa.Column('fqdn', sa.String(length=255), nullable=True), sa.Column( 'manufacturer', sa.Unicode(length=50), nullable=True), sa.Column( 'platform_name', sa.String(length=150), nullable=True), sa.Column('kernel_params', sa.Text(), nullable=True), sa.Column('progress', sa.Integer(), nullable=True), sa.Column( 'os_platform', sa.String(length=150), nullable=True), sa.Column('pending_addition', sa.Boolean(), nullable=True), sa.Column('pending_deletion', sa.Boolean(), nullable=True), sa.Column('error_type', sa.Enum( 'deploy', 'provision', 'deletion', name='node_error_type'), nullable=True), sa.Column( 'error_msg', sa.String(length=255), nullable=True), sa.Column('timestamp', sa.DateTime(), nullable=False), sa.Column('online', sa.Boolean(), nullable=True), sa.Column( 'agent_checksum', sa.String(length=40), nullable=True), sa.ForeignKeyConstraint(['cluster_id'], ['clusters.id'], ), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('mac'), sa.UniqueConstraint('uuid') ) op.create_table('tasks', sa.Column('id', sa.Integer(), nullable=False), sa.Column('cluster_id', sa.Integer(), nullable=True), sa.Column('uuid', sa.String(length=36), nullable=False), sa.Column('name', sa.Enum('super', 'deploy', 'deployment', 'provision', 'stop_deployment', 'reset_environment', 'node_deletion', 'cluster_deletion', 'check_before_deployment', 'check_networks', 'verify_networks', 'check_dhcp', 'verify_network_connectivity', 'redhat_setup', 'redhat_check_credentials', 'redhat_check_licenses', 'redhat_download_release', 'redhat_update_cobbler_profile', 'dump', 'capacity_log', name='task_name'), nullable=False), sa.Column('message', sa.Text(), nullable=True), sa.Column('status', sa.Enum( 'ready', 'running', 'error', name='task_status'), nullable=False), sa.Column('progress', sa.Integer(), nullable=True), sa.Column('cache', JSON(), nullable=True), sa.Column('result', JSON(), nullable=True), sa.Column('parent_id', sa.Integer(), nullable=True), sa.Column('weight', sa.Float(), nullable=True), sa.ForeignKeyConstraint(['cluster_id'], ['clusters.id'], ), sa.ForeignKeyConstraint(['parent_id'], ['tasks.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('networking_configs', sa.Column('id', sa.Integer(), nullable=False), sa.Column( 'discriminator', sa.String(length=50), nullable=True), sa.Column('cluster_id', sa.Integer(), nullable=True), sa.Column('dns_nameservers', JSON(), nullable=True), sa.Column('floating_ranges', JSON(), nullable=True), sa.ForeignKeyConstraint( ['cluster_id'], ['clusters.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) op.create_table('network_groups', sa.Column('id', sa.Integer(), nullable=False), sa.Column('name', sa.Enum('fuelweb_admin', 'storage', 'management', 'public', 'fixed', 'private', name='network_group_name'), nullable=False), sa.Column('release', sa.Integer(), nullable=True), sa.Column('cluster_id', sa.Integer(), nullable=True), sa.Column('vlan_start', sa.Integer(), nullable=True), sa.Column('cidr', sa.String(length=25), nullable=True), sa.Column('gateway', sa.String(length=25), nullable=True), sa.Column('meta', JSON(), nullable=True), sa.ForeignKeyConstraint(['cluster_id'], ['clusters.id'], ), sa.ForeignKeyConstraint(['release'], ['releases.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('attributes', sa.Column('id', sa.Integer(), nullable=False), sa.Column('cluster_id', sa.Integer(), nullable=True), sa.Column('editable', JSON(), nullable=True), sa.Column('generated', JSON(), nullable=True), sa.ForeignKeyConstraint(['cluster_id'], ['clusters.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('nova_network_config', sa.Column('id', sa.Integer(), nullable=False), sa.Column( 'fixed_networks_cidr', sa.String(length=25), nullable=True), sa.Column( 'fixed_networks_vlan_start', sa.Integer(), nullable=True), sa.Column( 'fixed_network_size', sa.Integer(), nullable=False), sa.Column( 'fixed_networks_amount', sa.Integer(), nullable=False), sa.Column('net_manager', sa.Enum( 'FlatDHCPManager', 'VlanManager', name='cluster_net_manager'), nullable=False), sa.ForeignKeyConstraint( ['id'], ['networking_configs.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('node_roles', sa.Column('id', sa.Integer(), nullable=False), sa.Column('role', sa.Integer(), nullable=True), sa.Column('node', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['node'], ['nodes.id'], ), sa.ForeignKeyConstraint( ['role'], ['roles.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) op.create_table('cluster_changes', sa.Column('id', sa.Integer(), nullable=False), sa.Column('cluster_id', sa.Integer(), nullable=True), sa.Column('node_id', sa.Integer(), nullable=True), sa.Column('name', sa.Enum( 'networks', 'attributes', 'disks', name='possible_changes'), nullable=False), sa.ForeignKeyConstraint(['cluster_id'], ['clusters.id'], ), sa.ForeignKeyConstraint( ['node_id'], ['nodes.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) op.create_table('node_attributes', sa.Column('id', sa.Integer(), nullable=False), sa.Column('node_id', sa.Integer(), nullable=True), sa.Column('volumes', JSON(), nullable=True), sa.Column('interfaces', JSON(), nullable=True), sa.ForeignKeyConstraint(['node_id'], ['nodes.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('notifications', sa.Column('id', sa.Integer(), nullable=False), sa.Column('cluster_id', sa.Integer(), nullable=True), sa.Column('node_id', sa.Integer(), nullable=True), sa.Column('task_id', sa.Integer(), nullable=True), sa.Column('topic', sa.Enum( 'discover', 'done', 'error', 'warning', name='notif_topic'), nullable=False), sa.Column('message', sa.Text(), nullable=True), sa.Column( 'status', sa.Enum('read', 'unread', name='notif_status'), nullable=False), sa.Column('datetime', sa.DateTime(), nullable=False), sa.ForeignKeyConstraint( ['cluster_id'], ['clusters.id'], ondelete='SET NULL'), sa.ForeignKeyConstraint( ['node_id'], ['nodes.id'], ondelete='SET NULL'), sa.ForeignKeyConstraint( ['task_id'], ['tasks.id'], ondelete='SET NULL'), sa.PrimaryKeyConstraint('id') ) op.create_table('node_bond_interfaces', sa.Column('id', sa.Integer(), nullable=False), sa.Column('node_id', sa.Integer(), nullable=False), sa.Column('name', sa.String(length=32), nullable=False), sa.Column('mac', LowercaseString(), nullable=True), sa.Column('state', sa.String(length=25), nullable=True), sa.Column('flags', JSON(), nullable=True), sa.Column('mode', sa.Enum('active-backup', 'balance-slb', 'lacp-balance-tcp', name='bond_mode'), nullable=False), sa.ForeignKeyConstraint( ['node_id'], ['nodes.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) op.create_table('ip_addrs', sa.Column('id', sa.Integer(), nullable=False), sa.Column('network', sa.Integer(), nullable=True), sa.Column('node', sa.Integer(), nullable=True), sa.Column('ip_addr', sa.String(length=25), nullable=False), sa.ForeignKeyConstraint( ['network'], ['network_groups.id'], ondelete='CASCADE'), sa.ForeignKeyConstraint( ['node'], ['nodes.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) op.create_table('ip_addr_ranges', sa.Column('id', sa.Integer(), nullable=False), sa.Column('network_group_id', sa.Integer(), nullable=True), sa.Column('first', sa.String(length=25), nullable=False), sa.Column('last', sa.String(length=25), nullable=False), sa.ForeignKeyConstraint( ['network_group_id'], ['network_groups.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('neutron_config', sa.Column('id', sa.Integer(), nullable=False), sa.Column('vlan_range', JSON(), nullable=True), sa.Column('gre_id_range', JSON(), nullable=True), sa.Column( 'base_mac', LowercaseString(), nullable=False), sa.Column( 'internal_cidr', sa.String(length=25), nullable=True), sa.Column( 'internal_gateway', sa.String(length=25), nullable=True), sa.Column('segmentation_type', sa.Enum( 'vlan', 'gre', name='segmentation_type'), nullable=False), sa.Column('net_l23_provider', sa.Enum( 'ovs', name='net_l23_provider'), nullable=False), sa.ForeignKeyConstraint( ['id'], ['networking_configs.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('pending_node_roles', sa.Column('id', sa.Integer(), nullable=False), sa.Column('role', sa.Integer(), nullable=True), sa.Column('node', sa.Integer(), nullable=True), sa.ForeignKeyConstraint(['node'], ['nodes.id'], ), sa.ForeignKeyConstraint( ['role'], ['roles.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) op.create_table('node_nic_interfaces', sa.Column('id', sa.Integer(), nullable=False), sa.Column('node_id', sa.Integer(), nullable=False), sa.Column('name', sa.String(length=128), nullable=False), sa.Column('mac', LowercaseString(), nullable=False), sa.Column('max_speed', sa.Integer(), nullable=True), sa.Column('current_speed', sa.Integer(), nullable=True), sa.Column('ip_addr', sa.String(length=25), nullable=True), sa.Column('netmask', sa.String(length=25), nullable=True), sa.Column('state', sa.String(length=25), nullable=True), sa.Column('parent_id', sa.Integer(), nullable=True), sa.ForeignKeyConstraint( ['node_id'], ['nodes.id'], ondelete='CASCADE'), sa.ForeignKeyConstraint( ['parent_id'], ['node_bond_interfaces.id'], ), sa.PrimaryKeyConstraint('id') ) op.create_table('net_bond_assignments', sa.Column('id', sa.Integer(), nullable=False), sa.Column('network_id', sa.Integer(), nullable=False), sa.Column('bond_id', sa.Integer(), nullable=False), sa.ForeignKeyConstraint( ['bond_id'], ['node_bond_interfaces.id'], ondelete='CASCADE'), sa.ForeignKeyConstraint( ['network_id'], ['network_groups.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') ) op.create_table('net_nic_assignments', sa.Column('id', sa.Integer(), nullable=False), sa.Column('network_id', sa.Integer(), nullable=False), sa.Column('interface_id', sa.Integer(), nullable=False), sa.ForeignKeyConstraint( ['interface_id'], ['node_nic_interfaces.id'], ondelete='CASCADE'), sa.ForeignKeyConstraint( ['network_id'], ['network_groups.id'], ondelete='CASCADE'), sa.PrimaryKeyConstraint('id') )
class Node(Base): __tablename__ = 'nodes' NODE_STATUSES = ('ready', 'discover', 'provisioning', 'provisioned', 'deploying', 'error') NODE_ERRORS = ('deploy', 'provision', 'deletion') id = Column(Integer, primary_key=True) cluster_id = Column(Integer, ForeignKey('clusters.id')) name = Column(Unicode(100)) status = Column(Enum(*NODE_STATUSES, name='node_status'), nullable=False, default='discover') meta = Column(JSON, default={}) mac = Column(LowercaseString(17), nullable=False, unique=True) ip = Column(String(15)) fqdn = Column(String(255)) manufacturer = Column(Unicode(50)) platform_name = Column(String(150)) 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(Enum(*NODE_ERRORS, name='node_error_type')) error_msg = Column(String(255)) timestamp = Column(DateTime, nullable=False) online = Column(Boolean, default=True) role_list = relationship("Role", secondary=NodeRoles.__table__, backref=backref("nodes", cascade="all,delete")) pending_role_list = relationship("Role", secondary=PendingNodeRoles.__table__, backref=backref("pending_nodes", cascade="all,delete")) attributes = relationship("NodeAttributes", backref=backref("node"), uselist=False, cascade="all,delete") interfaces = relationship("NodeNICInterface", backref="node", cascade="delete", order_by="NodeNICInterface.name") @property def uid(self): return str(self.id) @property def offline(self): return not self.online @property def network_data(self): from nailgun.network.manager import NetworkManager return NetworkManager.get_node_networks(self.id) @property def volume_manager(self): return VolumeManager(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 == 'error' 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 roles(self): return [role.name for role in self.role_list] @roles.setter def roles(self, new_roles): if not self.cluster: logger.warning(u"Attempting to assign roles to node " u"'{0}' which isn't added to cluster".format( self.name or self.id)) return self.role_list = db().query(Role).filter_by( release_id=self.cluster.release_id, ).filter( Role.name.in_(new_roles)).all() @property def pending_roles(self): return [role.name for role in self.pending_role_list] @property def all_roles(self): """Returns all roles, self.roles and self.pending_roles.""" return set(self.pending_roles + self.roles) @pending_roles.setter def pending_roles(self, new_roles): if not self.cluster: logger.warning(u"Attempting to assign pending_roles to node " u"'{0}' which isn't added to cluster".format( self.name or self.id)) return self.pending_role_list = db().query(Role).filter_by( release_id=self.cluster.release_id, ).filter( Role.name.in_(new_roles)).all() @property def admin_interface(self): """Iterate over interfaces, if admin subnet include ip address of current interface then return this interface. :raises: errors.CanNotFindInterface """ from nailgun.network.manager import NetworkManager admin_ng = NetworkManager.get_admin_network_group() for interface in self.interfaces: if admin_ng in interface.assigned_networks_list: return interface for interface in self.interfaces: ip_addr = interface.ip_addr if NetworkManager.is_ip_belongs_to_admin_subnet(ip_addr): return interface logger.warning(u'Cannot find admin interface for node ' 'return first interface: "%s"' % self.full_name) return self.interfaces[0] 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 = [] 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 = [] 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
class Node(Base): __tablename__ = 'nodes' 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')) group_id = Column(Integer, ForeignKey('nodegroups.id'), nullable=True) name = Column(Unicode(100)) status = Column(Enum(*consts.NODE_STATUSES, name='node_status'), nullable=False, default=consts.NODE_STATUSES.discover) meta = Column(JSON, default={}) mac = Column(LowercaseString(17), nullable=False, unique=True) ip = Column(String(15)) fqdn = Column(String(255)) 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(Enum(*consts.NODE_ERRORS, name='node_error_type')) error_msg = Column(String(255)) timestamp = Column(DateTime, nullable=False) online = Column(Boolean, default=True) node_type = Column(Integer) power_ip = Column(String(15)) role_list = relationship("Role", secondary=NodeRoles.__table__, backref=backref("nodes", cascade="all,delete")) role_associations = relationship("NodeRoles", viewonly=True) pending_role_associations = relationship("PendingNodeRoles", viewonly=True) pending_role_list = relationship("Role", secondary=PendingNodeRoles.__table__, backref=backref("pending_nodes", cascade="all,delete")) releaseos = None attributes = relationship("NodeAttributes", backref=backref("node"), uselist=False, cascade="all,delete") nic_interfaces = relationship("NodeNICInterface", backref="node", cascade="delete", order_by="NodeNICInterface.name") bond_interfaces = relationship("NodeBondInterface", backref="node", cascade="delete", 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(JSON, default=[]) replaced_provisioning_info = Column(JSON, default={}) user_set = Column(JSON, default={}) @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.network.manager import NetworkManager return NetworkManager.get_node_networks(self) @property def volume_manager(self): return VolumeManager(self) @property def release(self): return self.releaseos @release.setter def release(self, releaseid): release = db().query(Release).filter_by(id=releaseid, ).first() self.releaseos = release @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 ['error', 'provisioned'] 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 roles(self): return [role.name for role in self.role_list] @roles.setter def roles(self, new_roles): if not self.cluster: logger.warning(u"Attempting to assign roles to node " u"'{0}' which isn't added to cluster".format( self.name or self.id)) return if new_roles: self.role_list = db().query(Role).filter_by( release_id=self.cluster.release_id, ).filter( Role.name.in_(new_roles)).all() else: self.role_list = [] @property def pending_roles(self): return [role.name for role in self.pending_role_list] @property def all_roles(self): """Returns all roles, self.roles and self.pending_roles.""" return set(self.pending_roles + self.roles) @pending_roles.setter def pending_roles(self, new_roles): if not self.cluster: logger.warning(u"Attempting to assign pending_roles to node " u"'{0}' which isn't added to cluster".format( self.name or self.id)) return self.pending_role_list = db().query(Role).filter_by( release_id=self.cluster.release_id, ).filter( Role.name.in_(new_roles)).all() @property def admin_interface(self): """Iterate over interfaces, if admin subnet include ip address of current interface then return this interface. :raises: errors.CanNotFindInterface """ # TODO(enchantner): move to object from nailgun.network.manager import NetworkManager return NetworkManager.get_admin_interface(self) 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, phymaichineIp=None, phymachineMac=None): # 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 else: if bool(iface.get('ip')): if iface.get('mac').lower() == phymachineMac.lower(): iface['ip'] = phymaichineIp.lstrip().rstrip() result.append(self._clean_iface(iface)) data["interfaces"] = result self.meta = data def reset_name_to_default(self): """Reset name to default TODO(el): move to node REST object which will be introduced in 5.0 release """ self.name = u'Untitled ({0})'.format(self.mac[-5:])
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(LowercaseString(17)) assigned_networks_list = relationship( "NetworkGroup", secondary=NetworkBondAssignment.__table__, order_by="NetworkGroup.id") state = Column(String(25)) interface_properties = Column(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(JSON, default={}, nullable=False, server_default='{}') slaves = relationship("NodeNICInterface", backref="bond") @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) 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
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(LowercaseString(17), 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(String(25)) netmask = Column(String(25)) state = Column(String(25)) interface_properties = Column(JSON, default={}, nullable=False, server_default='{}') parent_id = Column(Integer, ForeignKey('node_bond_interfaces.id')) driver = Column(Text) bus_info = Column(Text) offloading_modes = Column(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 dictionary for easy 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
class Node(Base): __tablename__ = 'nodes' 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')) group_id = Column(Integer, ForeignKey('nodegroups.id'), nullable=True) name = Column(Unicode(100)) status = Column(Enum(*consts.NODE_STATUSES, name='node_status'), nullable=False, default=consts.NODE_STATUSES.discover) meta = Column(JSON, default={}) mac = Column(LowercaseString(17), nullable=False, unique=True) ip = Column(String(15)) fqdn = Column(String(255)) 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(Enum(*consts.NODE_ERRORS, name='node_error_type')) error_msg = Column(String(255)) timestamp = Column(DateTime, nullable=False) online = Column(Boolean, default=True) 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='{}') attributes = relationship("NodeAttributes", backref=backref("node"), uselist=False, cascade="all,delete") nic_interfaces = relationship("NodeNICInterface", backref="node", cascade="delete", order_by="NodeNICInterface.name") bond_interfaces = relationship("NodeBondInterface", backref="node", cascade="delete", 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(JSON, default=[]) replaced_provisioning_info = Column(JSON, default={}) @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.network.manager import NetworkManager return NetworkManager.get_node_networks(self) @property def volume_manager(self): # TODO(eli): will be moved into an extension. # Should be done as a part of blueprint: # https://blueprints.launchpad.net/fuel/+spec # /volume-manager-refactoring return VolumeManager(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 ['error', 'provisioned'] 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 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 def reset_name_to_default(self): """Reset name to default TODO(el): move to node REST object which will be introduced in 5.0 release """ self.name = u'Untitled ({0})'.format(self.mac[-5:]) @classmethod def delete_by_ids(cls, ids): db.query(Node).filter(Node.id.in_(ids)).delete('fetch')