Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
a7b8dd1
wip
loktev-d Apr 6, 2026
4357da0
wip
loktev-d Apr 6, 2026
c6eea11
wip
loktev-d Apr 6, 2026
aeedb02
wip
loktev-d Apr 6, 2026
d16fed3
wip
loktev-d Apr 6, 2026
e737138
wip
loktev-d Apr 6, 2026
afc481d
wip
loktev-d Apr 6, 2026
1bc8b68
wip
loktev-d Apr 6, 2026
b16d905
wip
loktev-d Apr 7, 2026
93695f2
wip
loktev-d Apr 7, 2026
745bc07
wip
loktev-d Apr 8, 2026
713d5a9
Merge branch 'main' into feat/network/dynamic-network-interfaces
loktev-d Apr 8, 2026
6e43337
wip
loktev-d Apr 9, 2026
d86a51e
add doc
loktev-d Apr 16, 2026
b5007c9
add e2e
loktev-d Apr 16, 2026
02d5695
Merge branch 'main' into feat/network/dynamic-network-interfaces
loktev-d Apr 16, 2026
4ec3be4
fix linter errors
loktev-d Apr 16, 2026
8ff2633
fix linter errors
loktev-d Apr 16, 2026
228e43c
Merge branch 'main' into feat/network/dynamic-network-interfaces
loktev-d May 8, 2026
f990e89
add fromCacheVersion
loktev-d May 8, 2026
2d91ed3
refactor isOnlyNonMainNetworksChanged
loktev-d May 8, 2026
b9dc54a
add validation for adding non existing networks
loktev-d May 12, 2026
c67e3dd
fix main network removal
loktev-d May 12, 2026
0bb955f
add networks to rbac
loktev-d May 12, 2026
72fd956
Merge branch 'main' into feat/network/dynamic-network-interfaces
loktev-d May 19, 2026
5324297
add handling of non-ready networks
loktev-d May 19, 2026
6b51fd5
add indexer for networks
loktev-d May 19, 2026
252e0bf
Merge branch 'main' into feat/network/dynamic-network-interfaces
loktev-d May 19, 2026
973a798
wip
loktev-d May 19, 2026
124f8fc
update cache version
loktev-d May 20, 2026
b8757f1
update cache version
loktev-d May 20, 2026
ea18b8b
Merge branch 'main' into feat/network/dynamic-network-interfaces
loktev-d May 20, 2026
c2192bd
fix vmmac removal when unplugging
loktev-d May 20, 2026
847b032
update cache
loktev-d May 25, 2026
208bcd1
Merge branch 'main' into feat/network/dynamic-network-interfaces
loktev-d May 25, 2026
119c84e
fixes in setnetwork
loktev-d May 25, 2026
4a4196f
remove main network name
loktev-d May 25, 2026
efcaa3e
docs: review
prismagod May 26, 2026
d360bb4
bump cache
loktev-d May 26, 2026
d0ff167
fix vmip/vmmac conflicts during restore
loktev-d May 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/components/versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ firmware:
libvirt: v10.9.0
edk2: stable202411
core:
3p-kubevirt: v1.6.2-v12n.35
3p-kubevirt: feat/core/network-hotplug-support
3p-containerized-data-importer: v1.60.3-v12n.19
distribution: 2.8.3
package:
Expand Down
26 changes: 14 additions & 12 deletions docs/USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1781,17 +1781,18 @@ If the virtual machine is in a shutdown state (`.status.phase: Stopped`), the ch

If the virtual machine is running (`.status.phase: Running`), the way the changes are applied depends on the type of change:

| Configuration block | How changes are applied |
|-----------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
| `.metadata.labels` | Applies immediately and propagates to the VM pod |
| `.metadata.annotations` | Applies immediately and propagates to the VM pod |
| `.spec.liveMigrationPolicy` | Applies immediately |
| `.spec.runPolicy` | Applies immediately |
| `.spec.disruptions.restartApprovalMode` | Applies immediately |
| `.spec.affinity` | EE, SE+: Applies immediately, CE: Only after VM restart |
| `.spec.nodeSelector` | EE, SE+: Applies immediately, CE: Only after VM restart |
| `.spec.cpu.cores` | May apply immediately if hotplug is enabled (EE, SE+), see [CPU hotplug](#cpu-hotplug); otherwise a restart is required. |
| `.spec.*` | Only after VM restart |
| Configuration block | How changes are applied |
|-----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `.metadata.labels` | Applies immediately and propagates to the VM pod |
| `.metadata.annotations` | Applies immediately and propagates to the VM pod |
| `.spec.liveMigrationPolicy` | Applies immediately |
| `.spec.runPolicy` | Applies immediately |
| `.spec.disruptions.restartApprovalMode` | Applies immediately |
| `.spec.affinity` | EE, SE+: Applies immediately, CE: Only after VM restart |
| `.spec.nodeSelector` | EE, SE+: Applies immediately, CE: Only after VM restart |
| `.spec.cpu.cores` | May apply immediately if hotplug is enabled (EE, SE+), see [CPU hotplug](#cpu-hotplug); otherwise a restart is required. |
| `.spec.networks` | Adding or removing `Network` or `ClusterNetwork` on a running VM applies without reboot. Changes to `Main` or the order of existing networks require a VM restart (see [Additional network interfaces](#additional-network-interfaces)) |
| `.spec.*` | Only after VM restart |

How to change the VM configuration in the web interface:

Expand Down Expand Up @@ -3101,7 +3102,8 @@ If you specify the main network, it must be the first entry in the `.spec.networ
Important considerations when working with additional network interfaces:

- The order of listing networks in `.spec.networks` determines the order in which interfaces are connected inside the virtual machine.
- Adding or removing additional networks takes effect only after the VM is rebooted.
- Adding or removing an additional network (`Network` or `ClusterNetwork`) on a running VM is applied live without reboot. ACPI indexes of existing interfaces are preserved across add/remove cycles, so interface names in the guest OS stay stable.
- Adding or removing the main network (`type: Main`) still requires a VM reboot, because it is tied to the pod's primary network interface and cannot be reconfigured on a running pod.
- To preserve the order of network interfaces inside the guest operating system, it is recommended to add new networks to the end of the `.spec.networks` list (do not change the order of existing ones).
- Network security policies (NetworkPolicy) do not apply to additional network interfaces.
- Network parameters (IP addresses, gateways, DNS, etc.) for additional networks are configured manually from within the guest OS (for example, using Cloud-Init).
Expand Down
26 changes: 14 additions & 12 deletions docs/USER_GUIDE.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -1799,17 +1799,18 @@ d8 k edit vm linux-vm

Если виртуальная машина работает (`.status.phase: Running`), то способ применения изменений зависит от их типа:

| Блок конфигурации | Как применяется |
|-----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| `.metadata.labels` | Сразу и распространяется на под ВМ |
| `.metadata.annotations` | Сразу и распространяется на под ВМ |
| `.spec.liveMigrationPolicy` | Сразу |
| `.spec.runPolicy` | Сразу |
| `.spec.disruptions.restartApprovalMode` | Сразу |
| `.spec.affinity` | EE, SE+ : Сразу, CE: Требуется перезапуск ВМ |
| `.spec.nodeSelector` | EE, SE+ : Сразу, CE: Требуется перезапуск ВМ |
| `.spec.cpu.cores` | Может применяться сразу при включённом hotplug (EE, SE+), см. [раздел «Горячее подключение CPU»](#горячее-подключение-cpu); иначе требуется перезапуск ВМ | |
| `.spec.*` | Требуется перезапуск ВМ |
| Блок конфигурации | Как применяется |
|-----------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `.metadata.labels` | Сразу и распространяется на под ВМ |
| `.metadata.annotations` | Сразу и распространяется на под ВМ |
| `.spec.liveMigrationPolicy` | Сразу |
| `.spec.runPolicy` | Сразу |
| `.spec.disruptions.restartApprovalMode` | Сразу |
| `.spec.affinity` | EE, SE+ : Сразу, CE: Требуется перезапуск ВМ |
| `.spec.nodeSelector` | EE, SE+ : Сразу, CE: Требуется перезапуск ВМ |
| `.spec.cpu.cores` | Может применяться сразу при включённом hotplug (EE, SE+), см. [раздел «Горячее подключение CPU»](#горячее-подключение-cpu); иначе требуется перезапуск ВМ |
| `.spec.networks` | Добавление и удаление `Network` и `ClusterNetwork` на работающей ВМ применяется без перезагрузки. Изменения `Main` или порядка уже указанных сетей требуют перезагрузки ВМ (см. [раздел «Дополнительные сетевые интерфейсы»](#дополнительные-сетевые-интерфейсы)) |
| `.spec.*` | Требуется перезапуск ВМ |

Как изменить конфигурацию ВМ в веб-интерфейсе:

Expand Down Expand Up @@ -3132,7 +3133,8 @@ EOF
Особенности и важные моменты работы с дополнительными сетевыми интерфейсами:

- порядок перечисления сетей в `.spec.networks` определяет порядок подключения интерфейсов внутри виртуальной машины;
- добавление или удаление дополнительных сетей вступает в силу только после перезагрузки ВМ;
- добавление или удаление дополнительной сети (`Network` или `ClusterNetwork`) на работающей ВМ применяется без перезагрузки. ACPI-индексы существующих интерфейсов сохраняются при добавлении/удалении, поэтому имена интерфейсов в гостевой ОС остаются стабильными;
- добавление или удаление основной сети (`type: Main`) по-прежнему требует перезагрузки ВМ, так как она связана с основным сетевым интерфейсом пода и не может быть изменена на работающем поде;
- чтобы сохранить порядок сетевых интерфейсов внутри гостевой операционной системы, рекомендуется добавлять новые сети в конец списка `.spec.networks` (не менять порядок уже существующих);
- политики сетевой безопасности (NetworkPolicy) не применяются к дополнительным сетевым интерфейсам;
- параметры сети (IP-адреса, шлюзы, DNS и т.д.) для дополнительных сетей настраиваются вручную изнутри гостевой ОС (например, с помощью Cloud-Init).
Expand Down
2 changes: 2 additions & 0 deletions images/virt-artifact/werf.inc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
image: {{ .ModuleNamePrefix }}{{ .ImageName }}-src-artifact
final: false
fromImage: builder/src
fromCacheVersion: "2026-05-20-3"
secrets:
- id: SOURCE_REPO
value: {{ $.SOURCE_REPO }}
Expand Down Expand Up @@ -44,6 +45,7 @@ packages:
image: {{ .ModuleNamePrefix }}{{ .ImageName }}
final: false
fromImage: {{ eq $.SVACE_ENABLED "false" | ternary "builder/golang-alt-1.25" "builder/golang-alt-svace-1.25" }}
fromCacheVersion: "2026-05-20-3"
mount:
{{- include "mount points for golang builds" . }}
secrets:
Expand Down
84 changes: 84 additions & 0 deletions images/virtualization-artifact/pkg/common/network/readiness.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
Copyright 2026 Flant JSC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package network

import (
"context"
"fmt"

k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/deckhouse/virtualization/api/core/v1alpha2"
)

var (
NetworkGVK = schema.GroupVersionKind{Group: "network.deckhouse.io", Version: "v1alpha1", Kind: "Network"}
ClusterNetworkGVK = schema.GroupVersionKind{Group: "network.deckhouse.io", Version: "v1alpha1", Kind: "ClusterNetwork"}
)

func SpecKey(ns v1alpha2.NetworksSpec) string {
return fmt.Sprintf("%s/%s", ns.Type, ns.Name)
}

func IsNetworkSpecReady(ctx context.Context, c client.Client, namespace string, ns v1alpha2.NetworksSpec) (bool, error) {
if ns.Type == v1alpha2.NetworksTypeMain {
return true, nil
}
obj := &unstructured.Unstructured{}
key := types.NamespacedName{Name: ns.Name}
switch ns.Type {
case v1alpha2.NetworksTypeClusterNetwork:
obj.SetGroupVersionKind(ClusterNetworkGVK)
case v1alpha2.NetworksTypeNetwork:
obj.SetGroupVersionKind(NetworkGVK)
key.Namespace = namespace
default:
return false, nil
}
if err := c.Get(ctx, key, obj); err != nil {
if k8serrors.IsNotFound(err) {
return false, nil
}
return false, err
}
return isReadyTrue(obj), nil
}

func isReadyTrue(obj *unstructured.Unstructured) bool {
conds, found, err := unstructured.NestedSlice(obj.Object, "status", "conditions")
if err != nil || !found {
return false
}
for _, c := range conds {
condMap, ok := c.(map[string]any)
if !ok {
continue
}
typ, _, _ := unstructured.NestedString(condMap, "type")
if typ != "Ready" {
continue
}
status, _, _ := unstructured.NestedString(condMap, "status")
return status == string(metav1.ConditionTrue)
}
return false
}
8 changes: 8 additions & 0 deletions images/virtualization-artifact/pkg/common/network/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ func CreateNetworkSpec(vm *v1alpha2.VirtualMachine, vmmacs []*v1alpha2.VirtualMa
macPool := NewMacAddressPool(vm, vmmacs)
var specs InterfaceSpecList

if len(vm.Spec.Networks) == 0 {
specs = append(specs, createMainInterfaceSpec(v1alpha2.NetworksSpec{
Type: v1alpha2.NetworksTypeMain,
ID: ptr.To(ReservedMainID),
}))
return specs
}

for _, net := range vm.Spec.Networks {
if net.Type == v1alpha2.NetworksTypeMain {
specs = append(specs, createMainInterfaceSpec(net))
Expand Down
13 changes: 8 additions & 5 deletions images/virtualization-artifact/pkg/common/network/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,16 @@ func HasMainNetworkStatus(networks []v1alpha2.NetworksStatus) bool {
}

func HasMainNetworkSpec(networks []v1alpha2.NetworksSpec) bool {
for _, network := range networks {
if network.Type == v1alpha2.NetworksTypeMain {
return true
return GetMainNetworkSpec(networks) != nil
}

func GetMainNetworkSpec(networks []v1alpha2.NetworksSpec) *v1alpha2.NetworksSpec {
for i := range networks {
if networks[i].Type == v1alpha2.NetworksTypeMain {
return &networks[i]
}
}

return false
return nil
}

type InterfaceSpec struct {
Expand Down
Loading
Loading