...

Source file src/kubevirt.io/client-go/api/schema_test.go

Documentation: kubevirt.io/client-go/api

     1  /*
     2   * This file is part of the KubeVirt project
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * Copyright 2017 Red Hat, Inc.
    17   *
    18   */
    19  
    20  package api
    21  
    22  import (
    23  	"bytes"
    24  	"encoding/json"
    25  	"fmt"
    26  	"text/template"
    27  
    28  	. "github.com/onsi/ginkgo/v2"
    29  	. "github.com/onsi/gomega"
    30  	v1 "k8s.io/api/core/v1"
    31  	"k8s.io/utils/pointer"
    32  
    33  	v12 "kubevirt.io/api/core/v1"
    34  )
    35  
    36  type NetworkTemplateConfig struct {
    37  	InterfaceConfig string
    38  }
    39  
    40  var exampleJSONFmt = `{
    41    "kind": "VirtualMachineInstance",
    42    "apiVersion": "kubevirt.io/%s",
    43    "metadata": {
    44      "name": "testvmi",
    45      "namespace": "default",
    46      "selfLink": "/apis/kubevirt.io/%s/namespaces/default/virtualmachineinstances/testvmi",
    47      "creationTimestamp": null
    48    },
    49    "spec": {
    50      "domain": {
    51        "resources": {
    52          "requests": {
    53            "memory": "8Mi"
    54          }
    55        },
    56        "cpu": {
    57          "cores": 3,
    58          "sockets": 1,
    59          "threads": 1,
    60          "model": "Conroe",
    61          "features": [
    62            {
    63              "name": "pcid",
    64              "policy": "require"
    65            },
    66            {
    67              "name": "monitor",
    68              "policy": "disable"
    69            }
    70          ],
    71          "dedicatedCpuPlacement": true
    72        },
    73        "firmware": {
    74          "uuid": "28a42a60-44ef-4428-9c10-1a6aee94627f"
    75        },
    76        "clock": {
    77          "utc": {},
    78          "timer": {
    79            "hpet": {
    80              "present": true
    81            },
    82            "kvm": {
    83              "present": true
    84            },
    85            "pit": {
    86              "present": true
    87            },
    88            "rtc": {
    89              "present": true
    90            },
    91            "hyperv": {
    92              "present": true
    93            }
    94          }
    95        },
    96        "features": {
    97          "acpi": {
    98            "enabled": false
    99          },
   100          "apic": {
   101            "enabled": true
   102          },
   103          "hyperv": {
   104            "relaxed": {
   105              "enabled": true
   106            },
   107            "vapic": {
   108              "enabled": false
   109            },
   110            "spinlocks": {
   111              "enabled": true,
   112              "spinlocks": 4096
   113            },
   114            "vpindex": {
   115              "enabled": false
   116            },
   117            "runtime": {
   118              "enabled": true
   119            },
   120            "synic": {
   121              "enabled": false
   122            },
   123            "synictimer": {
   124              "enabled": true,
   125              "direct": {
   126                "enabled": true
   127              }
   128            },
   129            "reset": {
   130              "enabled": false
   131            },
   132            "vendorid": {
   133              "enabled": true,
   134              "vendorid": "vendor"
   135            },
   136            "frequencies": {
   137              "enabled": false
   138            },
   139            "reenlightenment": {
   140              "enabled": false
   141            },
   142            "tlbflush": {
   143              "enabled": true
   144            }
   145          },
   146          "smm": {
   147            "enabled": true
   148          },
   149          "kvm": {
   150            "hidden": true
   151          },
   152          "pvspinlock": {
   153            "enabled": false
   154          }
   155        },
   156        "devices": {
   157          "disks": [
   158            {
   159              "name": "disk0",
   160              "disk": {
   161                "bus": "virtio"
   162              },
   163              "dedicatedIOThread": true
   164            },
   165            {
   166              "name": "cdrom0",
   167              "cdrom": {
   168                "bus": "virtio",
   169                "readonly": true,
   170                "tray": "open"
   171              }
   172            },
   173            {
   174              "name": "lun0",
   175              "lun": {
   176                "bus": "virtio",
   177                "readonly": true
   178              }
   179            },
   180            {
   181              "name": "disk1",
   182              "disk": {
   183                "bus": "virtio"
   184              },
   185              "serial": "sn-11223344"
   186            }
   187          ],
   188          "interfaces": [
   189            {
   190              "name": "default",
   191              {{.InterfaceConfig}}
   192            }
   193          ],
   194          "inputs": [
   195            {
   196              "bus": "virtio",
   197              "type": "tablet",
   198              "name": "tablet0"
   199            }
   200          ],
   201          "rng": {},
   202          "blockMultiQueue": true
   203        },
   204        "ioThreadsPolicy": "shared"
   205      },
   206      "volumes": [
   207        {
   208          "name": "disk0",
   209          "containerDisk": {
   210            "image": "test/image",
   211            "path": "/disk.img"
   212          }
   213        },
   214        {
   215          "name": "cdrom0",
   216          "cloudInitNoCloud": {
   217            "secretRef": {
   218              "name": "testsecret"
   219            },
   220            "networkDataSecretRef": {
   221              "name": "testnetworksecret"
   222            }
   223          }
   224        }
   225      ],
   226      "networks": [
   227        {
   228          "name": "default",
   229          "pod": {}
   230        }
   231      ]
   232    },
   233    "status": {
   234      "guestOSInfo": {},
   235      "runtimeUser": 0
   236    }
   237  }`
   238  
   239  var exampleJSON = fmt.Sprintf(exampleJSONFmt, v12.ApiLatestVersion, v12.ApiLatestVersion)
   240  
   241  var _ = Describe("Schema", func() {
   242  	//The example domain should stay in sync to the json above
   243  	var exampleVMI *v12.VirtualMachineInstance
   244  
   245  	BeforeEach(func() {
   246  		exampleVMI = NewMinimalVMI("testvmi")
   247  
   248  		pointer.BoolPtr(true)
   249  		exampleVMI.Spec.Domain.Devices.Disks = []v12.Disk{
   250  			{
   251  				Name: "disk0",
   252  				DiskDevice: v12.DiskDevice{
   253  					Disk: &v12.DiskTarget{
   254  						Bus:      v12.VirtIO,
   255  						ReadOnly: false,
   256  					},
   257  				},
   258  				DedicatedIOThread: pointer.BoolPtr(true),
   259  			},
   260  			{
   261  				Name: "cdrom0",
   262  				DiskDevice: v12.DiskDevice{
   263  					CDRom: &v12.CDRomTarget{
   264  						Bus:      v12.VirtIO,
   265  						ReadOnly: pointer.BoolPtr(true),
   266  						Tray:     "open",
   267  					},
   268  				},
   269  			},
   270  			{
   271  				Name: "lun0",
   272  				DiskDevice: v12.DiskDevice{
   273  					LUN: &v12.LunTarget{
   274  						Bus:      v12.VirtIO,
   275  						ReadOnly: true,
   276  					},
   277  				},
   278  			},
   279  			{
   280  				Name:   "disk1",
   281  				Serial: "sn-11223344",
   282  				DiskDevice: v12.DiskDevice{
   283  					Disk: &v12.DiskTarget{
   284  						Bus:      v12.VirtIO,
   285  						ReadOnly: false,
   286  					},
   287  				},
   288  			},
   289  		}
   290  
   291  		exampleVMI.Spec.Domain.Devices.Rng = &v12.Rng{}
   292  		exampleVMI.Spec.Domain.Devices.Inputs = []v12.Input{
   293  			{
   294  				Bus:  v12.VirtIO,
   295  				Type: "tablet",
   296  				Name: "tablet0",
   297  			},
   298  		}
   299  		exampleVMI.Spec.Domain.Devices.BlockMultiQueue = pointer.BoolPtr(true)
   300  
   301  		exampleVMI.Spec.Volumes = []v12.Volume{
   302  			{
   303  				Name: "disk0",
   304  				VolumeSource: v12.VolumeSource{
   305  					ContainerDisk: &v12.ContainerDiskSource{
   306  						Image: "test/image",
   307  						Path:  "/disk.img",
   308  					},
   309  				},
   310  			},
   311  			{
   312  				Name: "cdrom0",
   313  				VolumeSource: v12.VolumeSource{
   314  					CloudInitNoCloud: &v12.CloudInitNoCloudSource{
   315  						UserDataSecretRef: &v1.LocalObjectReference{
   316  							Name: "testsecret",
   317  						},
   318  						NetworkDataSecretRef: &v1.LocalObjectReference{
   319  							Name: "testnetworksecret",
   320  						},
   321  					},
   322  				},
   323  			},
   324  		}
   325  		exampleVMI.Spec.Domain.Features = &v12.Features{
   326  			ACPI:       v12.FeatureState{Enabled: pointer.BoolPtr(false)},
   327  			SMM:        &v12.FeatureState{Enabled: pointer.BoolPtr(true)},
   328  			APIC:       &v12.FeatureAPIC{Enabled: pointer.BoolPtr(true)},
   329  			KVM:        &v12.FeatureKVM{Hidden: true},
   330  			Pvspinlock: &v12.FeatureState{Enabled: pointer.BoolPtr(false)},
   331  			Hyperv: &v12.FeatureHyperv{
   332  				Relaxed:         &v12.FeatureState{Enabled: pointer.BoolPtr(true)},
   333  				VAPIC:           &v12.FeatureState{Enabled: pointer.BoolPtr(false)},
   334  				Spinlocks:       &v12.FeatureSpinlocks{Enabled: pointer.BoolPtr(true)},
   335  				VPIndex:         &v12.FeatureState{Enabled: pointer.BoolPtr(false)},
   336  				Runtime:         &v12.FeatureState{Enabled: pointer.BoolPtr(true)},
   337  				SyNIC:           &v12.FeatureState{Enabled: pointer.BoolPtr(false)},
   338  				SyNICTimer:      &v12.SyNICTimer{Enabled: pointer.BoolPtr(true), Direct: &v12.FeatureState{Enabled: pointer.BoolPtr(true)}},
   339  				Reset:           &v12.FeatureState{Enabled: pointer.BoolPtr(false)},
   340  				VendorID:        &v12.FeatureVendorID{Enabled: pointer.BoolPtr(true), VendorID: "vendor"},
   341  				Frequencies:     &v12.FeatureState{Enabled: pointer.BoolPtr(false)},
   342  				Reenlightenment: &v12.FeatureState{Enabled: pointer.BoolPtr(false)},
   343  				TLBFlush:        &v12.FeatureState{Enabled: pointer.BoolPtr(true)},
   344  			},
   345  		}
   346  		exampleVMI.Spec.Domain.Clock = &v12.Clock{
   347  			ClockOffset: v12.ClockOffset{
   348  				UTC: &v12.ClockOffsetUTC{},
   349  			},
   350  			Timer: &v12.Timer{
   351  				HPET:   &v12.HPETTimer{},
   352  				KVM:    &v12.KVMTimer{},
   353  				PIT:    &v12.PITTimer{},
   354  				RTC:    &v12.RTCTimer{},
   355  				Hyperv: &v12.HypervTimer{},
   356  			},
   357  		}
   358  		exampleVMI.Spec.Domain.Firmware = &v12.Firmware{
   359  			UUID: "28a42a60-44ef-4428-9c10-1a6aee94627f",
   360  		}
   361  		exampleVMI.Spec.Domain.CPU = &v12.CPU{
   362  			Cores:   3,
   363  			Sockets: 1,
   364  			Threads: 1,
   365  			Model:   "Conroe",
   366  			Features: []v12.CPUFeature{
   367  				{
   368  					Name:   "pcid",
   369  					Policy: "require",
   370  				},
   371  				{
   372  					Name:   "monitor",
   373  					Policy: "disable",
   374  				},
   375  			},
   376  			DedicatedCPUPlacement: true,
   377  		}
   378  		exampleVMI.Spec.Networks = []v12.Network{
   379  			v12.Network{
   380  				Name: "default",
   381  				NetworkSource: v12.NetworkSource{
   382  					Pod: &v12.PodNetwork{},
   383  				},
   384  			},
   385  		}
   386  
   387  		policy := v12.IOThreadsPolicyShared
   388  		exampleVMI.Spec.Domain.IOThreadsPolicy = &policy
   389  
   390  		v12.SetObjectDefaults_VirtualMachineInstance(exampleVMI)
   391  	})
   392  	Context("With example schema in json use pod network and bridge interface", func() {
   393  		It("Unmarshal json into struct", func() {
   394  			exampleVMI.Spec.Domain.Devices.Interfaces = []v12.Interface{
   395  				v12.Interface{
   396  					Name: "default",
   397  					InterfaceBindingMethod: v12.InterfaceBindingMethod{
   398  						Bridge: &v12.InterfaceBridge{},
   399  					},
   400  				},
   401  			}
   402  			networkTemplateData := NetworkTemplateConfig{InterfaceConfig: `"bridge": {}`}
   403  			tmpl, err := template.New("vmexample").Parse(exampleJSON)
   404  			Expect(err).ToNot(HaveOccurred())
   405  			var tpl bytes.Buffer
   406  			err = tmpl.Execute(&tpl, networkTemplateData)
   407  			Expect(err).ToNot(HaveOccurred())
   408  			newVMI := &v12.VirtualMachineInstance{}
   409  			err = json.Unmarshal(tpl.Bytes(), newVMI)
   410  			Expect(err).ToNot(HaveOccurred())
   411  			Expect(newVMI).To(Equal(exampleVMI))
   412  		})
   413  		It("Marshal struct into json", func() {
   414  			exampleVMI.Spec.Domain.Devices.Interfaces = []v12.Interface{
   415  				v12.Interface{
   416  					Name: "default",
   417  					InterfaceBindingMethod: v12.InterfaceBindingMethod{
   418  						Bridge: &v12.InterfaceBridge{},
   419  					},
   420  				},
   421  			}
   422  
   423  			networkTemplateData := NetworkTemplateConfig{InterfaceConfig: `"bridge": {}`}
   424  			tmpl, err := template.New("vmexample").Parse(exampleJSON)
   425  			Expect(err).ToNot(HaveOccurred())
   426  			var tpl bytes.Buffer
   427  			err = tmpl.Execute(&tpl, networkTemplateData)
   428  			Expect(err).ToNot(HaveOccurred())
   429  			exampleJSONParsed := tpl.String()
   430  			buf, err := json.MarshalIndent(*exampleVMI, "", "  ")
   431  			Expect(err).ToNot(HaveOccurred())
   432  			Expect(string(buf)).To(Equal(exampleJSONParsed))
   433  		})
   434  	})
   435  	Context("With example schema in json use pod network and slirp interface", func() {
   436  		It("Unmarshal json into struct", func() {
   437  			exampleVMI.Spec.Domain.Devices.Interfaces = []v12.Interface{
   438  				v12.Interface{
   439  					Name: "default",
   440  					InterfaceBindingMethod: v12.InterfaceBindingMethod{
   441  						DeprecatedSlirp: &v12.DeprecatedInterfaceSlirp{},
   442  					},
   443  				},
   444  			}
   445  			networkTemplateData := NetworkTemplateConfig{InterfaceConfig: `"slirp": {}`}
   446  			tmpl, err := template.New("vmexample").Parse(exampleJSON)
   447  			Expect(err).ToNot(HaveOccurred())
   448  			var tpl bytes.Buffer
   449  			err = tmpl.Execute(&tpl, networkTemplateData)
   450  			Expect(err).ToNot(HaveOccurred())
   451  			newVMI := &v12.VirtualMachineInstance{}
   452  			err = json.Unmarshal(tpl.Bytes(), newVMI)
   453  			Expect(err).ToNot(HaveOccurred())
   454  			Expect(newVMI).To(Equal(exampleVMI))
   455  		})
   456  		It("Marshal struct into json", func() {
   457  			exampleVMI.Spec.Domain.Devices.Interfaces = []v12.Interface{
   458  				v12.Interface{
   459  					Name: "default",
   460  					InterfaceBindingMethod: v12.InterfaceBindingMethod{
   461  						DeprecatedSlirp: &v12.DeprecatedInterfaceSlirp{},
   462  					},
   463  				},
   464  			}
   465  
   466  			networkTemplateData := NetworkTemplateConfig{InterfaceConfig: `"slirp": {}`}
   467  			tmpl, err := template.New("vmexample").Parse(exampleJSON)
   468  			Expect(err).ToNot(HaveOccurred())
   469  			var tpl bytes.Buffer
   470  			err = tmpl.Execute(&tpl, networkTemplateData)
   471  			Expect(err).ToNot(HaveOccurred())
   472  			exampleJSONParsed := tpl.String()
   473  			buf, err := json.MarshalIndent(*exampleVMI, "", "  ")
   474  			Expect(err).ToNot(HaveOccurred())
   475  			Expect(string(buf)).To(Equal(exampleJSONParsed))
   476  		})
   477  		It("Marshal struct into json with port configure", func() {
   478  			exampleVMI.Spec.Domain.Devices.Interfaces = []v12.Interface{
   479  				v12.Interface{
   480  					Name: "default",
   481  					InterfaceBindingMethod: v12.InterfaceBindingMethod{
   482  						DeprecatedSlirp: &v12.DeprecatedInterfaceSlirp{}},
   483  					Ports: []v12.Port{{Port: 80}},
   484  				},
   485  			}
   486  			networkTemplateData := NetworkTemplateConfig{InterfaceConfig: `"slirp": {},
   487              "ports": [
   488                {
   489                  "port": 80
   490                }
   491              ]`}
   492  
   493  			tmpl, err := template.New("vmexample").Parse(exampleJSON)
   494  			Expect(err).ToNot(HaveOccurred())
   495  			var tpl bytes.Buffer
   496  			err = tmpl.Execute(&tpl, networkTemplateData)
   497  			Expect(err).ToNot(HaveOccurred())
   498  			exampleJSONParsed := tpl.String()
   499  			buf, err := json.MarshalIndent(*exampleVMI, "", "  ")
   500  			Expect(err).ToNot(HaveOccurred())
   501  			Expect(string(buf)).To(Equal(exampleJSONParsed))
   502  		})
   503  	})
   504  })
   505  

View as plain text