Skip to content

Commit

Permalink
virtctl: remove hotplug/unplug from VMI
Browse files Browse the repository at this point in the history
hotplug/unplug will be allowed from VM only

Signed-off-by: Alona Paz <[email protected]>
  • Loading branch information
AlonaKaplan committed Jun 21, 2023
1 parent e1fdbb3 commit b132172
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 89 deletions.
55 changes: 14 additions & 41 deletions pkg/virtctl/network/dynamicifaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,11 @@ const (
var (
ifaceName string
networkAttachmentDefinitionName string
persist bool
)

type dynamicIfacesCmd struct {
kvClient kubecli.KubevirtClient
isPersistent bool
namespace string
kvClient kubecli.KubevirtClient
namespace string
}

func NewAddInterfaceCommand(clientConfig clientcmd.ClientConfig) *cobra.Command {
Expand All @@ -60,7 +58,7 @@ func NewAddInterfaceCommand(clientConfig clientcmd.ClientConfig) *cobra.Command
Example: usageAddInterface(),
Args: templates.ExactArgs(HotplugCmdName, 1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := newDynamicIfaceCmd(clientConfig, persist)
c, err := newDynamicIfaceCmd(clientConfig)
if err != nil {
return fmt.Errorf("error creating the `AddInterface` command: %w", err)
}
Expand All @@ -72,7 +70,6 @@ func NewAddInterfaceCommand(clientConfig clientcmd.ClientConfig) *cobra.Command
_ = cmd.MarkFlagRequired(networkAttachmentDefinitionNameArg)
cmd.Flags().StringVar(&ifaceName, ifaceNameArg, "", "Logical name of the interface to be plugged")
_ = cmd.MarkFlagRequired(ifaceNameArg)
cmd.Flags().BoolVar(&persist, "persist", false, "When set, the added interface will be persisted in the VM spec (if it exists)")

return cmd
}
Expand All @@ -84,7 +81,7 @@ func NewRemoveInterfaceCommand(clientConfig clientcmd.ClientConfig) *cobra.Comma
Example: usageRemoveInterface(),
Args: templates.ExactArgs(HotUnplugCmdName, 1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := newDynamicIfaceCmd(clientConfig, persist)
c, err := newDynamicIfaceCmd(clientConfig)
if err != nil {
return fmt.Errorf("error creating the `RemoveInterface` command: %w", err)
}
Expand All @@ -94,32 +91,25 @@ func NewRemoveInterfaceCommand(clientConfig clientcmd.ClientConfig) *cobra.Comma
cmd.SetUsageTemplate(templates.UsageTemplate())
cmd.Flags().StringVar(&ifaceName, ifaceNameArg, "", "Logical name of the interface to be plugged")
_ = cmd.MarkFlagRequired(ifaceNameArg)
cmd.Flags().BoolVar(&persist, "persist", false, "When set, the interface will be removed from the VM spec")

return cmd
}

func usageAddInterface() string {
usage := ` #Dynamically attach a network interface to a running VM.
{{ProgramName}} addinterface <vmi-name> --network-attachment-definition-name <network-attachment-definition name> --name <logical interface name>
#Dynamically attach a network interface to a running VM and persisting it in the VM spec. At next VM restart the network interface will be attached like any other network interface.
{{ProgramName}} addinterface <vm-name> --network-attachment-definition-name <network-attachment-definition name> --name <logical interface name> --persist
usage := ` #Dynamically attach a network interface to a running VM and persisting it in the VM spec. At next VM restart the network interface will be attached like any other network interface.
{{ProgramName}} addinterface <vm-name> --network-attachment-definition-name <network-attachment-definition name> --name <logical interface name>
`
return usage
}

func usageRemoveInterface() string {
usage := ` #Dynamically detach a network interface from a running VM.
usage := ` #Dynamically detach a network interface from a running VM and persisting it in the VM spec. At next VM restart the network interface won't be attached to the VM.
{{ProgramName}} removeinterface <vmi-name> --name <logical interface name>
#Dynamically detach a network interface from a running VM and persisting it in the VM spec. At next VM restart the network interface won't be attached to the VM.
{{ProgramName}} removeinterface <vm-name> --name <logical interface name> --persist
`
return usage
}

func newDynamicIfaceCmd(clientCfg clientcmd.ClientConfig, persistState bool) (*dynamicIfacesCmd, error) {
func newDynamicIfaceCmd(clientCfg clientcmd.ClientConfig) (*dynamicIfacesCmd, error) {
virtClient, err := kubecli.GetKubevirtClientFromClientConfig(clientCfg)
if err != nil {
return nil, fmt.Errorf("cannot obtain KubeVirt client: %v", err)
Expand All @@ -128,21 +118,11 @@ func newDynamicIfaceCmd(clientCfg clientcmd.ClientConfig, persistState bool) (*d
if err != nil {
return nil, err
}
return &dynamicIfacesCmd{kvClient: virtClient, isPersistent: persistState, namespace: namespace}, nil
return &dynamicIfacesCmd{kvClient: virtClient, namespace: namespace}, nil
}

func (dic *dynamicIfacesCmd) addInterface(vmName string, networkAttachmentDefinitionName string, name string) error {
if dic.isPersistent {
return dic.kvClient.VirtualMachine(dic.namespace).AddInterface(
context.Background(),
vmName,
&v1.AddInterfaceOptions{
NetworkAttachmentDefinitionName: networkAttachmentDefinitionName,
Name: name,
},
)
}
return dic.kvClient.VirtualMachineInstance(dic.namespace).AddInterface(
return dic.kvClient.VirtualMachine(dic.namespace).AddInterface(
context.Background(),
vmName,
&v1.AddInterfaceOptions{
Expand All @@ -153,18 +133,11 @@ func (dic *dynamicIfacesCmd) addInterface(vmName string, networkAttachmentDefini
}

func (dic *dynamicIfacesCmd) removeInterface(vmName string, name string) error {
if dic.isPersistent {
return dic.kvClient.VirtualMachine(dic.namespace).RemoveInterface(
context.Background(),
vmName,
&v1.RemoveInterfaceOptions{
Name: name,
},
)
}
return dic.kvClient.VirtualMachineInstance(dic.namespace).RemoveInterface(
return dic.kvClient.VirtualMachine(dic.namespace).RemoveInterface(
context.Background(),
vmName,
&v1.RemoveInterfaceOptions{Name: name},
&v1.RemoveInterfaceOptions{
Name: name,
},
)
}
51 changes: 3 additions & 48 deletions pkg/virtctl/network/dynamicifaces_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ var _ = Describe("Dynamic Interface Attachment", func() {
ctrl *gomock.Controller
kubeClient *fakek8sclient.Clientset
vm *kubecli.MockVirtualMachineInterface
vmi *kubecli.MockVirtualMachineInstanceInterface
)

BeforeEach(func() {
Expand Down Expand Up @@ -100,40 +99,21 @@ var _ = Describe("Dynamic Interface Attachment", func() {
})

It("hot-plug an interface works", func() {
vmi = kubecli.NewMockVirtualMachineInstanceInterface(ctrl)
mockVMIAddInterfaceEndpoints(vmi, vmName, testNetworkAttachmentDefinitionName, testIfaceName)

cmdArgs := append(requiredAddCmdFlags(testNetworkAttachmentDefinitionName, testIfaceName))
cmd := clientcmd.NewVirtctlCommand(buildDynamicIfaceCmd(network.HotplugCmdName, vmName, cmdArgs...)...)
Expect(cmd.Execute()).To(Succeed())
})

It("hot-plug an interface with the `--persist` option works", func() {
vm = kubecli.NewMockVirtualMachineInterface(ctrl)
mockVMAddInterfaceEndpoints(vm, vmName, testNetworkAttachmentDefinitionName, testIfaceName)

cmdArgs := append(requiredAddCmdFlags(testNetworkAttachmentDefinitionName, testIfaceName), "--persist")
cmdArgs := append(requiredAddCmdFlags(testNetworkAttachmentDefinitionName, testIfaceName))
cmd := clientcmd.NewVirtctlCommand(buildDynamicIfaceCmd(network.HotplugCmdName, vmName, cmdArgs...)...)
Expect(cmd.Execute()).To(Succeed())
})

It("hot-unplug an interface works", func() {
vmi = kubecli.NewMockVirtualMachineInstanceInterface(ctrl)
mockVMIRemoveInterfaceEndpoints(vmi, vmName, testIfaceName)

cmdArgs := []string{"--name", testIfaceName}
cmd := clientcmd.NewVirtctlCommand(buildDynamicIfaceCmd(network.HotUnplugCmdName, vmName, cmdArgs...)...)
Expect(cmd.Execute()).To(Succeed())
})

It("hot-unplug an interface with the `--persist` option works", func() {
vm = kubecli.NewMockVirtualMachineInterface(ctrl)
mockVMRemoveInterfaceEndpoints(vm, vmName, testIfaceName)

cmdArgs := []string{"--name", testIfaceName, "--persist"}
cmdArgs := []string{"--name", testIfaceName}
cmd := clientcmd.NewVirtctlCommand(buildDynamicIfaceCmd(network.HotUnplugCmdName, vmName, cmdArgs...)...)
e := cmd.Execute()
Expect(e).To(Succeed())
Expect(cmd.Execute()).To(Succeed())
})
})
})
Expand All @@ -156,31 +136,6 @@ func buildHotUnplugIfaceCmd(vmName string, requiredCmdArgs ...string) []string {
return append([]string{network.HotUnplugCmdName, vmName}, requiredCmdArgs...)
}

func mockVMIAddInterfaceEndpoints(vmi *kubecli.MockVirtualMachineInstanceInterface, vmName string, networkAttachmentDefinitionName string, name string) {
kubecli.MockKubevirtClientInstance.
EXPECT().
VirtualMachineInstance(k8smetav1.NamespaceDefault).
Return(vmi).
Times(1)
vmi.EXPECT().AddInterface(context.Background(), vmName, gomock.Any()).DoAndReturn(func(arg0, arg1, arg2 interface{}) interface{} {
Expect(arg2.(*v1.AddInterfaceOptions).NetworkAttachmentDefinitionName).To(Equal(networkAttachmentDefinitionName))
Expect(arg2.(*v1.AddInterfaceOptions).Name).To(Equal(name))
return nil
})
}

func mockVMIRemoveInterfaceEndpoints(vmi *kubecli.MockVirtualMachineInstanceInterface, vmName string, name string) {
kubecli.MockKubevirtClientInstance.
EXPECT().
VirtualMachineInstance(k8smetav1.NamespaceDefault).
Return(vmi).
Times(1)
vmi.EXPECT().RemoveInterface(context.Background(), vmName, gomock.Any()).DoAndReturn(func(arg0, arg1, arg2 interface{}) interface{} {
Expect(arg2.(*v1.RemoveInterfaceOptions).Name).To(Equal(name))
return nil
})
}

func mockVMAddInterfaceEndpoints(vm *kubecli.MockVirtualMachineInterface, vmName string, networkAttachmentDefinitionName string, name string) {
kubecli.MockKubevirtClientInstance.
EXPECT().
Expand Down

0 comments on commit b132172

Please sign in to comment.