mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-11-08 12:26:36 +00:00
Move the resourcemodifiers package from internal/ to pkg/ so that external plugins, such as Restore Item Action (RIA) plugins, can import and reuse Velero's built-in resource modifier implementation. Due to Go's internal package visibility restrictions, external plugins cannot import packages located under internal/. Relocating resourcemodifiers to pkg/ allows plugins to evaluate and apply resource modifier rules to in-memory resource objects prior to validation or restore execution, ensuring consistent behavior with the Velero server without duplicate code. Update all internal import paths and add an unreleased changelog entry. Fixes #10668 Signed-off-by: Adam Zhang <adam.zhang@broadcom.com>
104 lines
2.9 KiB
Go
104 lines
2.9 KiB
Go
package resourcemodifiers
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
|
|
jsonpatch "github.com/evanphx/json-patch/v5"
|
|
"github.com/sirupsen/logrus"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
)
|
|
|
|
type JSONPatch struct {
|
|
Operation string `json:"operation"`
|
|
From string `json:"from,omitempty"`
|
|
Path string `json:"path"`
|
|
Value string `json:"value,omitempty"`
|
|
}
|
|
|
|
func (p *JSONPatch) ToString() string {
|
|
if addQuotes(&p.Value) {
|
|
return fmt.Sprintf(`{"op": "%s", "from": "%s", "path": "%s", "value": "%s"}`, p.Operation, p.From, p.Path, p.Value)
|
|
}
|
|
return fmt.Sprintf(`{"op": "%s", "from": "%s", "path": "%s", "value": %s}`, p.Operation, p.From, p.Path, p.Value)
|
|
}
|
|
|
|
func addQuotes(value *string) bool {
|
|
if *value == "" {
|
|
return true
|
|
}
|
|
// if value is escaped, remove escape and add quotes
|
|
// this is useful for scenarios where boolean, null and numbers are required to be set as string.
|
|
if strings.HasPrefix(*value, "\"") && strings.HasSuffix(*value, "\"") {
|
|
*value = strings.TrimPrefix(*value, "\"")
|
|
*value = strings.TrimSuffix(*value, "\"")
|
|
return true
|
|
}
|
|
// if value is null, then don't add quotes
|
|
if *value == "null" {
|
|
return false
|
|
}
|
|
// if value is a boolean, then don't add quotes
|
|
if strings.ToLower(*value) == "true" || strings.ToLower(*value) == "false" {
|
|
return false
|
|
}
|
|
// if value is a json object or array, then don't add quotes.
|
|
if strings.HasPrefix(*value, "{") || strings.HasPrefix(*value, "[") {
|
|
return false
|
|
}
|
|
// if value is a number, then don't add quotes
|
|
if _, err := strconv.ParseFloat(*value, 64); err == nil {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
type JSONPatcher struct {
|
|
patches []JSONPatch `yaml:"patches"`
|
|
}
|
|
|
|
func (p *JSONPatcher) Patch(u *unstructured.Unstructured, logger logrus.FieldLogger) (*unstructured.Unstructured, error) {
|
|
modifiedObjBytes, err := p.applyPatch(u)
|
|
if err != nil {
|
|
if errors.Is(err, jsonpatch.ErrTestFailed) {
|
|
logger.Infof("Test operation failed for JSON Patch %s", err.Error())
|
|
return u.DeepCopy(), nil
|
|
}
|
|
return nil, fmt.Errorf("error in applying JSON Patch %s", err.Error())
|
|
}
|
|
|
|
updated := &unstructured.Unstructured{}
|
|
err = updated.UnmarshalJSON(modifiedObjBytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error in unmarshalling modified object %s", err.Error())
|
|
}
|
|
|
|
return updated, nil
|
|
}
|
|
|
|
func (p *JSONPatcher) applyPatch(u *unstructured.Unstructured) ([]byte, error) {
|
|
patchBytes := p.patchArrayToByteArray()
|
|
jsonPatch, err := jsonpatch.DecodePatch(patchBytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error in decoding json patch %s", err.Error())
|
|
}
|
|
|
|
objBytes, err := u.MarshalJSON()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error in marshaling object %s", err.Error())
|
|
}
|
|
|
|
return jsonPatch.Apply(objBytes)
|
|
}
|
|
|
|
func (p *JSONPatcher) patchArrayToByteArray() []byte {
|
|
var patches []string
|
|
for _, patch := range p.patches {
|
|
patches = append(patches, patch.ToString())
|
|
}
|
|
patchesStr := strings.Join(patches, ",\n\t")
|
|
return []byte(fmt.Sprintf(`[%s]`, patchesStr))
|
|
}
|