Skip to content

Commit

Permalink
Add JSONPath for DSL Remove operation
Browse files Browse the repository at this point in the history
  • Loading branch information
Yulypso committed Jun 7, 2021
1 parent 5d1a071 commit c05c4fb
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 82 deletions.
17 changes: 16 additions & 1 deletion TestDeployments/pod-1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,33 @@ metadata:
spec:
securityContext:
runAsUser: 3000
initContainers:
- name: init0
image: yulypso/node-app:v0.0.1
- name: init1
image: yulypso/node-app:v0.0.1
- name: init2
image: yulypso/node-app:v0.0.1
containers:
- name: node-app
- name: node-app0
image: yulypso/node-app:v0.0.1
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 512Mi
cpu: "1"
- name: node-app1
image: yulypso/node-app:v0.0.1
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 512Mi
cpu: "1"
- name: node-app2
image: yulypso/node-app:v0.0.1
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 512Mi
cpu: "1"

11 changes: 10 additions & 1 deletion WebhookServer/Config/Patches/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,16 @@
"remove":
[
{
"path": "/spec/securityContext/runAsUser"
"path": "/spec/securityContext/"
},
{
"path": "/metadata/labels/app"
},
{
"path": "/spec/containers/2"
},
{
"path": "/spec/initContainers"
}
],
"replace":
Expand Down
197 changes: 120 additions & 77 deletions WebhookServer/pods/mutate-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,58 +64,6 @@ func getPatches(config Config, namespace Namespace, operations []admissioncontro
return operations
}

/* dsl, pod, dsl (jsonpath)*/
func sanitizeOperation(currentOp int, podData interface{}, jp string, operations []admissioncontroller.PatchOperation, operationsLen int) (admissioncontroller.PatchOperation, string, []admissioncontroller.PatchOperation, int, error) {
patchOps := operations[currentOp]
var err error
matched, _ := regexp.MatchString("^/([/A-Za-z0-9](\\[[\\*\\d]*\\])?(\\[[\\+\\d]*\\])?)+([A-Za-z0-9]|(\\[[\\*\\d]*\\])|(\\[[\\+\\d]*\\]))$", patchOps.Path)

if matched && patchOps.Op == "add" {
l := 1
/* Add k new operations and remove operation containing [*] */
if strings.Contains(jp, "[*]") {
li := strings.Index(jp, "[*]")
pattern := jp[:li]
l = getSubPathLength(podData, pattern)

path := JsonPathToPath(jp)
for j := 0; j < l; j++ {
if j == 0 {
path = strings.Replace(path, "*", strconv.Itoa(j), 1)
err = errors.New("removing [*] operation")
} else {
path = strings.Replace(path, strconv.Itoa(j-1), strconv.Itoa(j), 1)
}
fmt.Println(path)
fmt.Println(patchOps.Value)
operations = append(operations, admissioncontroller.AddPatchOperation(path, patchOps.Value))
operationsLen++
}
} else if strings.Contains(patchOps.Path, "[+]") {
/* Search for a free index if [+] */
i := 0
err = nil
jp = strings.Replace(jp, "[+]", "["+strconv.Itoa(i)+"]", 1)
for {
fmt.Println(jp)
_, err := jsonpath.Read(podData, jp)
if err != nil {
fmt.Println("-> found free id", i)
patchOps.Path = strings.Replace(patchOps.Path, "[+]", "/"+strconv.Itoa(i), 1)
return patchOps, jp, operations, operationsLen, nil
} else {
fmt.Println("-> id already exist")
i++
li := strings.LastIndex(jp, "["+strconv.Itoa(i-1)+"]")
jp = jp[:li] + strings.Replace(jp[li:], "["+strconv.Itoa(i-1)+"]", "["+strconv.Itoa(i)+"]", 1)
}
}
}
return patchOps, jp, operations, operationsLen, err
}
return patchOps, "", operations, operationsLen, errors.New("error: path regex unmatch: " + patchOps.Path)
}

func removeInvalidOperation(index int, operations []admissioncontroller.PatchOperation) []admissioncontroller.PatchOperation {
return append(operations[:index], operations[index+1:]...)
}
Expand All @@ -131,24 +79,31 @@ func getOperationPerType(t string, op []admissioncontroller.PatchOperation) []ad
}

func getSubPathLength(podData interface{}, pattern string) int {
a, _ := jsonpath.Read(podData, "$.spec.containers") // ex: $.spec.container
a, _ := jsonpath.Read(podData, pattern) // pattern ex: $.spec.container
b, _ := json.Marshal(a)

var res []interface{}
json.Unmarshal(b, &res)
return len(res)
}

func appendAtIndex(index int, operations []admissioncontroller.PatchOperation, op admissioncontroller.PatchOperation) []admissioncontroller.PatchOperation {
last := len(operations) - 1
operations = append(operations, operations[last])
copy(operations[index+1:], operations[index:last])
operations[index] = op
return operations
}

/*
* To JSONPath
* Path to JSONPath
*/
func pathToJsonPath(s string) string {
jsonPath := "$"
path := strings.Split(strings.TrimSpace(s), "/")

for _, item := range path[1:] {
if _, err := strconv.Atoi(item); err == nil { // if item looks like an integer
fmt.Printf("%q looks like a number.\n", item)
if _, err := strconv.Atoi(item); err == nil {
jsonPath += "[" + item + "]"
} else {
jsonPath += "." + item
Expand All @@ -157,6 +112,9 @@ func pathToJsonPath(s string) string {
return jsonPath
}

/*
* JSONPath to Path
*/
func JsonPathToPath(s string) string {
path := ""
jsonPath := strings.Split(strings.TrimSpace(s), ".")
Expand All @@ -171,16 +129,91 @@ func JsonPathToPath(s string) string {
return path
}

/*func valueToJsonPath(s string) {
jsonPath := "$"
}*/
func sanitizeOperation(currentOp int, podData interface{}, jp string, operations []admissioncontroller.PatchOperation, operationsLen int) (admissioncontroller.PatchOperation, string, []admissioncontroller.PatchOperation, int, error) {
patchOps := operations[currentOp]
var err error
err = nil
var matched bool

func verifyAdd(op []admissioncontroller.PatchOperation, r *admission.AdmissionRequest) []admissioncontroller.PatchOperation {
switch patchOps.Op {
case "add":
if matched, _ = regexp.MatchString("^/([/A-Za-z0-9](\\[[*+]\\])?(\\[[\\d]*\\])?)+([A-Za-z0-9]|(\\[[*+]\\])|(\\[[\\d]*\\]))$", patchOps.Path); !matched {
break
}
l := 1
/* Add k new operations and remove operation containing [*] */
if strings.Contains(jp, "[*]") {
li := strings.Index(jp, "[*]")
pattern := jp[:li]
l = getSubPathLength(podData, pattern)

path := JsonPathToPath(jp)
for j := 0; j < l; j++ {
if j == 0 {
path = strings.Replace(path, "*", strconv.Itoa(j), 1)
err = errors.New("removing [*] operation")
} else {
path = strings.Replace(path, strconv.Itoa(j-1), strconv.Itoa(j), 1)
}
fmt.Println(path)
fmt.Println(patchOps.Value)
operations = appendAtIndex(currentOp+j+1, operations, admissioncontroller.AddPatchOperation(path, patchOps.Value))
operationsLen++
}
} else if strings.Contains(patchOps.Path, "[+]") {
/* Search for a free index if [+] */
/*i := 0
jp = strings.Replace(jp, "[+]", "["+strconv.Itoa(i)+"]", 1)
for {
fmt.Println(jp)
_, err := jsonpath.Read(podData, jp)
if err != nil {
fmt.Println("-> found free id", i)
patchOps.Path = strings.Replace(patchOps.Path, "[+]", "/"+strconv.Itoa(i), 1)
return patchOps, jp, operations, operationsLen, nil
} else {
fmt.Println("-> id already exist")
i++
li := strings.LastIndex(jp, "["+strconv.Itoa(i-1)+"]")
jp = jp[:li] + strings.Replace(jp[li:], "["+strconv.Itoa(i-1)+"]", "["+strconv.Itoa(i)+"]", 1)
}
}*/
// TEST
li := strings.Index(jp, "[+]")
pattern := jp[:li]
l = getSubPathLength(podData, pattern)
patchOps.Path = strings.Replace(patchOps.Path, "[+]", "/"+strconv.Itoa(l), 1)
fmt.Println(patchOps.Path)
}
return patchOps, jp, operations, operationsLen, err
case "remove":
if matched, _ = regexp.MatchString("^/([/A-Za-z0-9](\\[[*+]\\])?(\\[[\\d]*\\])?)+([A-Za-z0-9]|(\\[[*+]\\])|(\\[[\\d]*\\]))$", patchOps.Path); !matched {
break
}
return patchOps, jp, operations, operationsLen, err
case "replace":
break
case "mandatorydata":
break
case "forbiddendata":
break
default:
return patchOps, jp, operations, operationsLen, err
}
return patchOps, "", operations, operationsLen, errors.New("error: path regex unmatch: " + patchOps.Path)
}

func verifyOperations(op []admissioncontroller.PatchOperation, r *admission.AdmissionRequest) []admissioncontroller.PatchOperation {
fmt.Print("\nOperation list\n")
fmt.Println(op)

fmt.Print("\nOperation Add list\n")
operations := getOperationPerType("add", op)
var operations []admissioncontroller.PatchOperation
fmt.Print("\nOperation (dev) list\n")
adds := getOperationPerType("add", op)
removes := getOperationPerType("remove", op)

operations = append(operations, adds...)
operations = append(operations, removes...)
fmt.Println(operations)
operationsLen := len(operations)

Expand Down Expand Up @@ -215,23 +248,33 @@ func verifyAdd(op []admissioncontroller.PatchOperation, r *admission.AdmissionRe
i--
operationsLen--
} else {
/* try to read in pod JSONPath */
_, err = jsonpath.Read(podData, jp)
if err != nil {
fmt.Println("field doesn't exist: good to add")
} else {
fmt.Println("field already exist: bad to add")
fmt.Printf("Removing operation: ")
fmt.Println(operations[i])
operations = removeInvalidOperation(i, operations)
i--
operationsLen--
if operations[i].Op == "add" {
/* try to read in pod JSONPath */
_, err = jsonpath.Read(podData, jp)
if err != nil {
fmt.Println("field doesn't exist: good to add")
} else {
fmt.Println("field already exist: bad to add")
fmt.Printf("Removing operation: ")
fmt.Println(operations[i])
operations = removeInvalidOperation(i, operations)
i--
operationsLen--
}
} else if operations[i].Op == "remove" {
_, err = jsonpath.Read(podData, jp)
if err != nil {
fmt.Println("field doesn't exist: bad to remove")
fmt.Printf("Removing operation: ")
fmt.Println(operations[i])
operations = removeInvalidOperation(i, operations)
i--
operationsLen--
} else {
fmt.Println("field exist: good to remove")
}
}
}
}
return operations
}

func verifyRemove(operations []admissioncontroller.PatchOperation, r *admission.AdmissionRequest) []admissioncontroller.PatchOperation {
return operations
}
5 changes: 2 additions & 3 deletions WebhookServer/pods/mutate.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ func mutateCreate(config Config) admissioncontroller.AdmitFunc {
// TODO
}

/* ISSUE (Error pod deployment)
/* DOING (Error pod deployment)
* Add: Check if the field already exist or not, (if YES, remove the operation from operations)
* Delete: Check if the field already exist or not, if NOT, remove the operation from operations
*/
operations = verifyAdd(operations, r)
operations = verifyRemove(operations, r)
operations = verifyOperations(operations, r)
admissioncontroller.PrintPatchOperations(operations)

return &admissioncontroller.Result{
Expand Down

0 comments on commit c05c4fb

Please sign in to comment.