mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-09 14:43:24 +00:00
service_action: use unstructured to marshal selective fields (#3789)
* use unstructured to marshal selective fields Signed-off-by: Alay Patel <alay1431@gmail.com> * add a sample test for string port in applied config Signed-off-by: Alay Patel <alay1431@gmail.com> * update changelog Signed-off-by: Alay Patel <alay1431@gmail.com>
This commit is contained in:
1
changelogs/unreleased/3789-alaypatel07
Normal file
1
changelogs/unreleased/3789-alaypatel07
Normal file
@@ -0,0 +1 @@
|
||||
use unstructured to marshal selective fields for service restore action
|
||||
@@ -18,6 +18,7 @@ package restore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -84,14 +85,51 @@ func deleteNodePorts(service *corev1api.Service) error {
|
||||
explicitNodePorts := sets.NewString()
|
||||
lastAppliedConfig, ok := service.Annotations[annotationLastAppliedConfig]
|
||||
if ok {
|
||||
appliedService := new(corev1api.Service)
|
||||
if err := json.Unmarshal([]byte(lastAppliedConfig), appliedService); err != nil {
|
||||
appliedServiceUnstructured := new(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(lastAppliedConfig), appliedServiceUnstructured); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
for _, port := range appliedService.Spec.Ports {
|
||||
if port.NodePort > 0 {
|
||||
explicitNodePorts.Insert(port.Name)
|
||||
ports, bool, err := unstructured.NestedSlice(*appliedServiceUnstructured, "spec", "ports")
|
||||
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
if bool {
|
||||
for _, port := range ports {
|
||||
p, ok := port.(map[string]interface{})
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
nodePort, nodePortBool, err := unstructured.NestedFieldNoCopy(p, "nodePort")
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if nodePortBool {
|
||||
nodePortInt := 0
|
||||
switch nodePort.(type) {
|
||||
case int32:
|
||||
nodePortInt = int(nodePort.(int32))
|
||||
case float64:
|
||||
nodePortInt = int(nodePort.(float64))
|
||||
case string:
|
||||
nodePortInt, err = strconv.Atoi(nodePort.(string))
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
if nodePortInt > 0 {
|
||||
portName, ok := p["name"]
|
||||
if !ok {
|
||||
// unnamed port
|
||||
explicitNodePorts.Insert("")
|
||||
} else {
|
||||
explicitNodePorts.Insert(portName.(string))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,21 @@ func svcJSON(ports ...corev1api.ServicePort) string {
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func svcJSONFromUnstructured(ports ...map[string]interface{}) string {
|
||||
svc := map[string]interface{}{
|
||||
"spec": map[string]interface{}{
|
||||
"ports": ports,
|
||||
},
|
||||
}
|
||||
|
||||
data, err := json.Marshal(svc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func TestServiceActionExecute(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
@@ -233,6 +248,38 @@ func TestServiceActionExecute(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unnamed nodePort should be deleted when named a string nodePort specified in annotation",
|
||||
obj: corev1api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "svc-1",
|
||||
Annotations: map[string]string{
|
||||
annotationLastAppliedConfig: svcJSONFromUnstructured(map[string]interface{}{"name": "http", "nodePort": "8080"}),
|
||||
},
|
||||
},
|
||||
Spec: corev1api.ServiceSpec{
|
||||
Ports: []corev1api.ServicePort{
|
||||
{
|
||||
NodePort: 8080,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
restore: builder.ForRestore(api.DefaultNamespace, "").Result(),
|
||||
expectedRes: corev1api.Service{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "svc-1",
|
||||
Annotations: map[string]string{
|
||||
annotationLastAppliedConfig: svcJSONFromUnstructured(map[string]interface{}{"name": "http", "nodePort": "8080"}),
|
||||
},
|
||||
},
|
||||
Spec: corev1api.ServiceSpec{
|
||||
Ports: []corev1api.ServicePort{
|
||||
{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "named nodePort should be preserved when specified in annotation",
|
||||
obj: corev1api.Service{
|
||||
|
||||
Reference in New Issue
Block a user