独立网络配置¶
https://bugs.launchpad.net/ironic/+bug/2113769
本文档提出了一种在裸机节点管理期间配置交换机端口属性的机制。目标是使 Ironic 能够支持此功能,而无需将网络任务委托给 Neutron。这种新机制由 Conductor 中的现有网络驱动程序接口启动,会将实际的交换机端口配置委托给一个独立的 service。该 service 可以与现有的 Ironic service 协同部署,也可以由专门负责网络设备的运维团队独立管理,部署在单独的服务器上。
问题描述¶
运维人员希望自动化网络配置,以便在无需手动预配置交换机端口的情况下部署节点。节点通过一个或多个网络接口连接到交换机,每个接口都需要针对其预期用途进行特定的相邻交换机配置。这些接口可能需要接入端口或中继端口配置。此外,可能需要链路聚合来增强节点的网络容量或冗余性。通常,在 Ironic 部署节点之前,必须手动完成这些配置操作。
管理节点和网络设备通常由不同的组织团队负责。这种责任划分引入了关于谁可以修改交换机配置以及修改程度的安全问题。由于精细的授权因交换机厂商而异,因此该 service 应提供基本的控制措施来解决运维人员的安全问题,从而限制 Ironic 可以尝试的操作。
提议的变更¶
提出的实现方案是引入一个新的独立 service 来执行与网络交换设备的交互。这个新的 service 包含一个 JSON RPC 前端 API,供在 Conductor 上下文中运行的网络驱动程序访问。在裸机节点的正常管理生命周期中,节点上定义的任何端口都将像当前实现一样由网络驱动程序处理。
驱动程序的责任是确保相关的交换机配置根据端口的 switchport 和 portchannel 信息进行更新,这些信息包含在端口的 extra 属性中。现有的网络驱动程序可以与 Neutron 子系统交互来管理交换机配置,但本设计中提出的解决方案消除了包含其他 OpenStack 组件的需求,而是提供了一个端到端的 Ironic 专用解决方案。
注意
使用 extra 属性是一种启用新功能的临时方法。长远目标是用一组新的 API 模型和端点来取代这些属性,这些模型和端点专门用于新功能。我们的意图是使用 extra 属性来探索此新功能的使用,以此来验证新功能。一旦用例得到验证并更好地理解,我们就可以将 extra 属性的新内容提升到一组新的 API 模型和端点。
注意
独立 service 可能需要考虑向同一交换机同时发出命令的影响。在某些情况下,这可能导致意外结果。独立 service 应该被设计成能够优雅地处理这种情况。
┌──────────────────────┐
│ │
│ Ironic API │
│ │
└──────────┬───────────┘
│
│ ┌────────────────────────┐
┌──────────▼───────────┐ │ │
│ │ │ Ironic Standalone │
│ Ironic Conductor │ │ Networking Service │ ┌───────────────┐
│ ┌───────────┤ │ ┌────────────┤ │ │
│ │ Network ┼─────► │ Switch ┼─────► TOR Switch │
│ │ Driver │ │ │ Driver │ │ │
└──────────└───────────┘ └───────────└────────────┘ └───────────────┘
备选方案¶
如果我们假设所有网络交换机都实现了一些形式的细粒度访问控制,这些访问控制可以应用于特定的用户凭据,那么我们可以放弃构建访问控制机制,而是依赖于分配给 Ironic service 的用户凭据授予的访问权限。这将消除将此机制作为独立 service 实现的需要,而是可以直接通过自定义网络驱动程序嵌入到 Conductor 中,该驱动程序可以直接与网络交换机交互。
┌──────────────────────┐
│ │
│ Ironic API │
│ │
└──────────┬───────────┘
│
│
┌──────────▼───────────┐
│ │
│ Ironic Conductor │ ┌───────────────────┐
│ ┌───────────┤ │ │
│ │ Network ┼────────►─ TOR Switch │
│ │ Driver │ │ │
└──────────└───────────┘ └───────────────────┘
当然,访问控制要求只是拥有独立 service 的原因之一,我们需要评估其他要求是否也会促使我们走向独立 service(例如,将实际的交换机交互在单独的 service 上执行对于性能/可扩展性是否有益?假设驱动程序操作对此其他 service 同步,那么性能/可扩展性可能不会因拥有单独的 service 而得到改善)。
数据模型影响¶
目前没有计划更改现有的数据模型。交换机端口配置细节将存储在现有端口对象的 extra 属性中;因此,现有的端口相关数据模型模式可以在不进行修改的情况下使用。
状态机影响¶
此功能实现的机制依赖于通过 LLDP 发现收集交换机端口细节。为此,节点交换机端口必须在注册之前启用,以便在初始检查操作期间收集 LLDP 信息。这提出了三个问题。
1. 交换机端口必须在节点的初始注册之前启用,并且必须配置在能够运行节点初始检查的 VLAN 上。也就是说,VLAN 必须可路由到 API 端点。
2. 为了确保对于被停用然后重新注册的节点,注册过程是可重复的,我们必须确保交换机端口在未被使用时返回到上述 (1) 中描述的 VLAN。我们称此 VLAN 为“空闲”VLAN,并且我们确保实验性独立驱动程序始终在此 VLAN 上回退,以移除端口配置中的任何其他网络。
3. 由于“空闲”VLAN 可能与节点主接口的最终 VLAN 不同,因此在注册主机时提供的任何静态网络配置数据可能在检查过程中无效或不适用。
为了解决这些问题,应该考虑对节点状态机进行两项更改,并提出了两个额外的配置选项
恢复空闲网络
如果配置了“空闲”网络 VLAN,则在从端口移除网络时,它将恢复到交换机端口上。
这确保了裸机硬件可以通过维护交换机端口上的“空闲”VLAN,从而无缝地重新注册和重新配置,从而在后续检查期间启用 LLDP 信息收集。
检查网络配置
一个新的配置选项 inspector.force_dhcp 修改了检查过程的行为
检查状态:在托管检查期间,启用时,此选项可确保忽略静态网络数据。ramdisk 将改为依赖于所有接口上的 DHCP 来获取网络配置。
网络发现:自动在所有接口上启用 LLDP 收集,以确保全面的网络拓扑发现
这些更改并未引入新的配置状态,而是增强了现有的状态转换,以更好地支持独立的网络场景,在这些场景中,完整的网络拓扑发现和一致的交换机端口配置对于自动化的裸机生命周期管理至关重要。
REST API 影响¶
目前没有计划更改现有的 API 模式或端点。交换机端口配置细节存储在端口或端口组的 extra 属性中;因此,现有的端口和端口组相关 API 端点和模式可以在不进行修改的情况下使用。当与端口对象相关时,extra 属性应填充符合此模式的字典。
{
"$schema": "https://schema.json.js.cn/draft-07/schema#",
"title": "Switchport Configuration",
"description": "Schema for defining switchport configurations based on
mode (trunk or access)",
"type": "object",
"properties": {
"switchport": {
"type": "object",
"properties": {
"mode": {
"type": "string",
"enum": ["trunk", "access"]
},
"native_vlan": {
"type": "integer",
"minimum": 1,
"description": "The native VLAN ID for the switchport. If not
supplied then the switch global default VLAN ID is used."
},
"allowed_vlans": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
},
"minItems": 1,
"description": "List of allowed VLANs for trunk mode. Only
applicable, and is mandatory, if mode=trunk."
}
},
"required": [
"mode",
]
}
},
"required": [
"switchport",
],
}
例如,以下数据存储在端口的 extra 属性中,以指定其交换机端口必须配置为具有特定默认 VLAN 和一组允许 VLAN 的中继端口。
{'switchport':
{'mode': 'trunk',
'native_vlan': 1,
'allowed_vlans': [2, 3, 4]
}
}
以下数据存储在端口的 extra 属性中,以指定其交换机端口必须配置为具有特定默认 VLAN 的接入端口。
{'switchport':
{'mode': 'access',
'native_vlan': 1,
}
}
如果与端口组对象相关,则支持类似的模式,但与交换机端口通道只有差异。
{
"$schema": "https://schema.json.js.cn/draft-07/schema#",
"title": "Switchport Configuration",
"description": "Schema for defining switch port channel configurations
based on mode (e.g., trunk or access) and aggregation mode (e.g., LACP
or static)",
"type": "object",
"properties": {
"portchannel": {
"type": "object",
"properties": {
"mode": {
"type": "string",
"enum": ["trunk", "access"]
},
"native_vlan": {
"type": "integer",
"minimum": 1,
"description": "The native VLAN ID for the switchport. If not
supplied then the switch global default VLAN ID is used."
},
"allowed_vlans": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
},
"minItems": 1,
"description": "List of allowed VLANs for trunk mode. Only
applicable, and is mandatory, if mode=trunk."
},
"aggregation_mode": {
"type": "string",
"enum": ["lacp", "static"],
},
},
"required": [
"mode",
"aggregation_mode",
]
}
},
"required": [
"portchannel",
],
}
例如,以下数据存储在端口组的 extra 属性中,以指定必须在交换机上创建和管理的相应端口通道。端口通道应配置为具有特定默认 VLAN 和一组允许 VLAN 的中继端口,并在 LACP 链路聚合模式下运行。
{'portchannel':
{'mode': 'trunk',
'native_vlan': 1,
'allowed_vlans': [2, 3, 4],
'aggregation_mode': 'lacp'
}
}
以下数据存储在端口组的 extra 属性中,以指定必须在交换机上创建和管理的相应端口通道。端口通道必须配置为具有特定默认 VLAN 的接入端口,并在静态链路聚合模式下运行。
{'portchannel':
{'mode': 'access',
'native_vlan': 1,
'aggregation_mode': 'static'
}
}
客户端 (CLI) 影响¶
无
“openstack baremetal” CLI¶
无
“openstacksdk”¶
无
RPC API 影响¶
Conductor RPC API:无
独立 Service API:驱动程序和独立网络 service 之间的 RPC API 可以定义如下
方法 |
签名 |
|---|---|
update_port |
{"switch_id": "xx:xx:xx:xx:xx:xx",
"port_name": "xxx",
"description": "xxx",
"mode": "[access|trunk]",
"native_vlan": n,
"allowed_vlans": [x, y, z],
"portchannel_name": "xxx"}
|
reset_port |
{"switch_id": "xx:xx:xx:xx:xx:xx",
"port_name": "xxx",
"native_vlan": n,
"allowed_vlans": [x, y, z],
"default_vlan": n}
|
disable_port |
{"switch_id": "xx:xx:xx:xx:xx:xx",
"port_name": "xxx"}
|
create_portchannel |
{"switch_ids": ["xx:xx:xx:xx:xx:xx",...]
"portchannel_name": "xxx",
"description": "xxx",
"mode": "[access|trunk]",
"default_vlan": {1 to 4094},
"allowed_vlans": [x, y, z],
"aggregation_mode": "[lacp|static]"}
|
delete_portchannel |
{"switch_ids": ["xx:xx:xx:xx:xx:xx",...],
"port_name": "xxx"}
|
驱动程序 API 影响¶
未更改现有的驱动程序接口。预计此功能可以在现有 Networking Driver API 的定义中实现。这意味着现有的 Conductor 工作流不需要进行修改。新的网络驱动程序必须以确保交换机端口配置在裸机节点通过完整的管理生命周期状态机过渡时正确更新的方式实现定义的抽象接口。
驱动程序的正确操作依赖于端口填充 LLDP 信息,形式为 link_local_connection 属性。这确保了驱动程序可以将配置与交换机上的正确端口关联。
接口 |
动作 |
|---|---|
port_changed |
如果需要,更新交换机端口配置以匹配。 |
portgroup_changed |
如果需要,更新交换机端口配置以匹配。 |
vif_attach |
N/A。此驱动程序不期望或支持 VIF 附件。 |
vif_detach |
N/A。此驱动程序不期望或支持 VIF 附件。 |
vif_list |
N/A。此驱动程序不期望或支持 VIF 附件。 |
get_current_vif |
N/A。此驱动程序不期望或支持 VIF 附件。 |
add_provisioning_network |
根据配置文件中配置的每个端口配置端口;否则,根据其定义的 switchport |
remove_provisioning_network |
将端口重置为交换机端口默认值,或者如果已配置则重置为“空闲”网络。 |
configure_tenant_networks |
根据其 |
unconfigure_tenant_networks |
将端口重置为交换机端口默认值,或者如果已配置则重置为“空闲”网络。 |
add_cleaning_network |
根据配置文件中配置的每个端口配置端口;否则,根据其定义的 switchport |
remove_cleaning_network |
将端口重置为交换机端口默认值,或者如果已配置则重置为“空闲”网络。 |
validate_rescue |
N/A |
add_rescuing_network |
根据配置文件中配置的每个端口配置端口;否则,根据其定义的 switchport |
remove_rescuing_network |
将端口重置为交换机端口默认值,或者如果已配置则重置为“空闲”网络。 |
validate_inspection |
N/A |
add_inspection_network |
根据配置文件中配置的每个端口配置端口;否则,根据其定义的 switchport |
remove_inspection_network |
将端口重置为交换机端口默认值,或者如果已配置则重置为“空闲”网络。 |
need_power_on |
False |
get_node_network_data |
从配置的端口构建网络数据 |
add_servicing_network |
根据配置文件中配置的每个端口配置端口;否则,根据其定义的 switchport |
remove_servicing_network |
将端口重置为交换机端口默认值,或者如果已配置则重置为“空闲”网络。 |
Nova 驱动程序影响¶
无
Ramdisk 影响¶
无
安全影响¶
RPC API 身份验证/授权:此设计的意图是创建一个独立的 service,该 service 作为 Ironic 子系统的一部分存在,但可以由专门负责管理网络设备的团队单独运行和管理。在这种情况下,该过程必须具有足够的安全控制,以确保只有授权用户才能访问其配置文件和 RPC API。需要进行讨论以确定要使用的方法。
对交换机资源的访问控制:理想情况下,交换机操作系统固有的 ACL 机制将用于限制对分配给独立网络 service 的用户实体的交换机资源的访问,但由于本设计的一个目标是不假设所有交换机厂商都支持对资源的细粒度控制,因此添加从独立 service 的配置文件中直接控制对资源的访问的能力可能是有益的。
要控制的资源可能包括
允许/拒绝 VLAN ID
允许/拒绝端口列表
允许端口通道管理
其他最终用户影响¶
如“状态机影响”部分所述。新节点必须在注册之前将其交换机端口配置在检查 VLAN 上。
可扩展性影响¶
将交换机操作作为裸机节点管理的一部分将无疑会增加完成节点操作所需的时间。具体增加多少时间将完全取决于网络交换机上运行的管理软件的响应速度。在启动节点之前配置交换机端口是绝对要求;因此,通过使配置异步化,将 Conductor 过程与交换机配置分离可能不可行。
随着实现的进展,这将需要评估。
性能影响¶
参见上文“可扩展性影响”。
其他部署者影响¶
为了定义用于提供程序网络的交换机端口配置细节,必须使用以下配置文件属性。对于每个网络类,如果配置文件中未提供任何值,则将使用端口的 extra.switchport 或 extra.portchannel 属性,如果端口或端口组不包含任何此类属性,则驱动程序将忽略它。可以将以下属性添加到主 ironic.conf 文件中。
[networking]
idle_network = <[access|trunk]/vlan-id{1 to 4094}>
provisioning_network = <[access|trunk]/vlan-id={1 to 4094}>
cleaning_network = <[access|trunk]/vlan-id={1 to 4094}>
servicing_network = <[access|trunk]/vlan-id={1 to 4094}>
# Optionally, for inspection if a separate network is used
# inspection_network = <[access|trunk]/vlan-id={1 to 4094}>
示例
[networking]
idle_network = <[access|trunk]/vlan-id=9
provisioning_network = access/vlan-id=10
cleaning_network = access/vlan-id=11
servicing_network = trunk/vlan-id=12
# Optionally, for inspection if a separate network is used
# inspection_network = access/vlan-id=13
为了将交换机端口配置细节传播到交换机,必须向新的网络 service 提供访问和配置交换机所需的信息。这包括用户凭据、网络地址以及访问交换机所需的任何其他属性。
以下示例是基于两个 Neutron ML2 机制驱动程序 ([1], [2]) 的混合方案,并结合了一些额外的访问控制信息来限制对交换机资源的访问。它包含有关最终允许不同类型的驱动程序实现与交换机交互的条款。可以将这些属性添加到提供给独立网络 service 的配置文件中。
[DEFAULT]
enabled_devices = <list of switch names>
allowed_vlans = <list of allowed vlans, takes precedence over denied_vlans
if provided>
denied_vlans = <list of denied vlans, superseded by allowed_vlans if
provided>
allowed_ports = <list of allowed port names, takes precedence over
denied_ports if provided>
denied_ports = <list of denied port names, superseded by allowed_ports if
provided>
portchannels_allowed = [true/false]
[<switch name>]
driver = <driver name>
switch_id = <switch mac address>
host = <switch management ip address>
username = <username>
password = <password, if driver support basic auth>
key_filename = <ssh private key file absolute path, if driver supports ssh>
hostkey_verify = <[true|false]>
allowed_vlans = <list of allowed vlans, takes precedence over denied_vlans
if provided. Overrides global value if supplied>
denied_vlans = <list of denied vlans, superseded by allowed_vlans if
provided. Overrides global value if supplied>
allowed_ports = <list of allowed port names, takes precedence over
denied_ports if provided. Overrides global value if supplied>
denied_ports = <list of denied port names, superseded by allowed_ports if
provided, Overrides global value if supplied>
portchannels_allowed = [true/false, Overrides global value if supplied]
示例
[DEFAULT]
enabled_devices = netconf-based-device.example.net,cli-based-device.example.net
allowed_vlans = 3,4,5
denied_vlans = 6,7,8
[netconf-based-device.example.net]
driver = netconf-openconfig
switch_id = <switch mac address>
host = <switch management ip address>
username = user
key_filename = /etc/ironic/ssh_keys/device_a_sshkey
hostkey_verify = false
[cli-based-device.example.net]
driver = netmiko_cisco_ios
switch_id = <switch mac address>
host = <switch management ip address>
username = user
password = secret
开发人员影响¶
无
实现¶
负责人¶
- 主要负责人
alegacy
- 其他贡献者
n/a
工作项¶
定义独立 service 的 RPC API
将 networking-generic-switch 分割成一个可重用的库,不包含任何 Neutron 关联。
实现独立 service
实现与独立 service 交互的网络驱动程序
实现交换机驱动程序(使用 networking-generic-switch 包的重构部分,参见上文)以与网络设备交互
重新审视
extra属性的使用,并用新的 API 模型和端点替换。
依赖项¶
network-generic-switch 库包含用于实现与网络交换机交互的代码。不幸的是,这段代码与 Neutron API 依赖性纠缠在一起。我们希望尽可能地重用该库来实现本服务的一部分,但必须移除其 API 和实现中的 Neutron 特定方面。一种可能的方案是重构该库,将 Neutron 特定的部分保留在实际的 networking-generic-switch 库中,而将交换机特定的部分移动到一个新的库中,该库可以从 networking-generic-switch 项目和这个新的独立服务中分别引用。
测试¶
单元测试
可能需要一个带有存根驱动程序的 Devstack 设置来模拟交换机配置。
升级和向后兼容性¶
无
文档影响¶
待定
参考资料¶
[0] https://specs.openstack.org/openstack/ironic-specs/specs/not-implemented/mercury.html
[1] https://etherpad.opendev.org/p/ironic-standalone-networking
[2] https://docs.openstack.org/networking-baremetal/latest/index.html
[3] https://docs.openstack.org/networking-generic-switch/latest/index.html