Skip to content

Commit

Permalink
Merge pull request openshift#3187 from nunnatsa/jsonpatch
Browse files Browse the repository at this point in the history
CNV-23418: unsupported escape hatch mechanism custom HS/KV vms
  • Loading branch information
openshift-merge-bot[bot] authored Nov 15, 2023
2 parents 15ce0af + bdff8d3 commit 48df9ee
Show file tree
Hide file tree
Showing 9 changed files with 600 additions and 27 deletions.
5 changes: 4 additions & 1 deletion api/hypershift/v1beta1/hostedcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,11 @@ const (
// See https://github.com/openshift/enhancements/blob/master/enhancements/authentication/pod-security-admission.md
PodSecurityAdmissionLabelOverrideAnnotation = "hypershift.openshift.io/pod-security-admission-label-override"

//DisableMonitoringServices introduces introduces an option to disable monitor services IBM Cloud do not use.
//DisableMonitoringServices introduces an option to disable monitor services IBM Cloud do not use.
DisableMonitoringServices = "hypershift.openshift.io/disable-monitoring-services"

// JSONPatchAnnotation allow modifying the kubevirt VM template using jsonpatch
JSONPatchAnnotation = "hypershift.openshift.io/kubevirt-vm-jsonpatch"
)

// HostedClusterSpec is the desired behavior of a HostedCluster.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/clarketm/json v1.14.1
github.com/coreos/ignition/v2 v2.14.0
github.com/docker/distribution v2.8.2+incompatible
github.com/evanphx/json-patch/v5 v5.6.0
github.com/go-logr/logr v1.2.4
github.com/go-logr/zapr v1.2.4
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
Expand Down Expand Up @@ -110,7 +111,6 @@ require (
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
Expand Down
75 changes: 68 additions & 7 deletions hypershift-operator/controllers/nodepool/kubevirt/kubevirt.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package kubevirt

import (
"bytes"
"encoding/json"
"fmt"
"strings"

"k8s.io/utils/pointer"
"kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"

jsonpatch "github.com/evanphx/json-patch/v5"
corev1 "k8s.io/api/core/v1"
apiresource "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
kubevirtv1 "kubevirt.io/api/core/v1"
"kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
capikubevirt "sigs.k8s.io/cluster-api-provider-kubevirt/api/v1alpha1"

hyperv1 "github.com/openshift/hypershift/api/hypershift/v1beta1"
Expand Down Expand Up @@ -142,7 +144,6 @@ func virtualMachineTemplateBase(nodePool *hyperv1.NodePool, bootImage BootImage)

dvSource := bootImage.getDVSourceForVMTemplate()

runAlways := kubevirtv1.RunStrategyAlways
kvPlatform := nodePool.Spec.Platform.Kubevirt

if kvPlatform.Compute != nil {
Expand All @@ -159,7 +160,7 @@ func virtualMachineTemplateBase(nodePool *hyperv1.NodePool, bootImage BootImage)

template := &capikubevirt.VirtualMachineTemplateSpec{
Spec: kubevirtv1.VirtualMachineSpec{
RunStrategy: &runAlways,
RunStrategy: ptr.To(kubevirtv1.RunStrategyAlways),
Template: &kubevirtv1.VirtualMachineInstanceTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
Expand Down Expand Up @@ -273,13 +274,13 @@ func virtualMachineTemplateBase(nodePool *hyperv1.NodePool, bootImage BootImage)

if kvPlatform.NetworkInterfaceMultiQueue != nil &&
*nodePool.Spec.Platform.Kubevirt.NetworkInterfaceMultiQueue == hyperv1.MultiQueueEnable {
template.Spec.Template.Spec.Domain.Devices.NetworkInterfaceMultiQueue = pointer.Bool(true)
template.Spec.Template.Spec.Domain.Devices.NetworkInterfaceMultiQueue = ptr.To(true)
}

return template
}

func MachineTemplateSpec(nodePool *hyperv1.NodePool, bootImage BootImage, hcluster *hyperv1.HostedCluster) *capikubevirt.KubevirtMachineTemplateSpec {
func MachineTemplateSpec(nodePool *hyperv1.NodePool, bootImage BootImage, hcluster *hyperv1.HostedCluster) (*capikubevirt.KubevirtMachineTemplateSpec, error) {
vmTemplate := virtualMachineTemplateBase(nodePool, bootImage)

vmTemplate.Spec.Template.Spec.Affinity = &corev1.Affinity{
Expand Down Expand Up @@ -330,12 +331,72 @@ func MachineTemplateSpec(nodePool *hyperv1.NodePool, bootImage BootImage, hclust
vmTemplate.ObjectMeta.Namespace = hcluster.Spec.Platform.Kubevirt.Credentials.InfraNamespace
}

if err := applyJsonPatches(nodePool, hcluster, vmTemplate); err != nil {
return nil, err
}

return &capikubevirt.KubevirtMachineTemplateSpec{
Template: capikubevirt.KubevirtMachineTemplateResource{
Spec: capikubevirt.KubevirtMachineSpec{
VirtualMachineTemplate: *vmTemplate,
BootstrapCheckSpec: capikubevirt.VirtualMachineBootstrapCheckSpec{CheckStrategy: "none"},
},
},
}, nil
}

func applyJsonPatches(nodePool *hyperv1.NodePool, hcluster *hyperv1.HostedCluster, tmplt *capikubevirt.VirtualMachineTemplateSpec) error {
hcAnn, hcOK := hcluster.Annotations[hyperv1.JSONPatchAnnotation]
npAnn, npOK := nodePool.Annotations[hyperv1.JSONPatchAnnotation]

if !hcOK && !npOK { // nothing to do
return nil
}

//tmplt.Spec.Template.Spec.Networks[0].Multus.NetworkName
buff := &bytes.Buffer{}
dec := json.NewEncoder(buff)
err := dec.Encode(tmplt.Spec.Template)
if err != nil {
return fmt.Errorf("json: failed to encode the vm template: %w", err)
}

templateBytes := buff.Bytes()

if hcOK {
if err = applyJsonPatch(&templateBytes, hcAnn); err != nil {
return err
}
}

if npOK {
if err = applyJsonPatch(&templateBytes, npAnn); err != nil {
return err
}
}

buff = bytes.NewBuffer(templateBytes)
enc := json.NewDecoder(buff)

if err = enc.Decode(tmplt.Spec.Template); err != nil {
return fmt.Errorf("json: failed to decode the vm template: %w", err)
}

return nil
}

func applyJsonPatch(tmplt *[]byte, patch string) error {
patches, err := jsonpatch.DecodePatch([]byte(patch))
if err != nil {
return fmt.Errorf("failed to parse the %s annotation; wrong jsonpatch format: %w", hyperv1.JSONPatchAnnotation, err)
}

opts := jsonpatch.NewApplyOptions()
opts.EnsurePathExistsOnAdd = true
*tmplt, err = patches.ApplyWithOptions(*tmplt, opts)
if err != nil {
return fmt.Errorf("failed to apply json patch annotation: %w", err)
}

return nil
}
Loading

0 comments on commit 48df9ee

Please sign in to comment.