Skip to content

Commit

Permalink
bisect works. changed Spec data structure to map[string]interface{} f…
Browse files Browse the repository at this point in the history
…rom map[string]string so that bisect will work. Have to ensure that spechistory and other methods will still work
  • Loading branch information
djarotech committed Aug 16, 2018
1 parent d23e0d3 commit f2c1270
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 31 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export PATH=$PATH:/usr/local/go/bin <br/>
curl -L https://github.com/coreos/etcd/releases/download/v3.2.18/etcd-v3.2.18-linux-amd64.tar.gz -o etcd-v3.2.18-linux-amd64.tar.gz && tar xzvf etcd-v3.2.18-linux-amd64.tar.gz && /bin/cp -f etcd-v3.2.18-linux-amd64/{etcd,etcdctl} /usr/bin && rm -rf etcd-v3.2.18-linux-amd64* <br/>
**4. Install Docker**<br/>
Follow steps here: reference: https://docs.docker.com/install/linux/docker-ce/ubuntu/#set-up-the-repository <br/>
docker version <br/> //check if it is installed
docker version //check if it is installed <br/>

set up your go workspace, set the GOPATH to it. this is where all your go code should be. <br/>
mkdir $HOME/goworkspace <br/>
Expand Down Expand Up @@ -153,10 +153,10 @@ kubectl.sh get --raw "/apis/kubeprovenance.cloudark.io/v1/namespaces/default/pos
kubectl.sh get --raw "/apis/kubeprovenance.cloudark.io/v1/namespaces/default/postgreses/client25/diff?start=1&end=2&field=databases"
```

5) Find out in which version the field 'abc' was given value 'def'
5) Find out in which version the user 'pallavi' was given password 'pass123'

```
kubectl.sh get --raw "/apis/kubeprovenance.cloudark.io/v1/namespaces/default/postgreses/client25/bisect?field=abc&value=def"
kubectl get --raw "/apis/kubeprovenance.cloudark.io/v1/namespaces/default/postgreses/client25/bisect?field1=username&value1=pallavi&field2=password&value2=pass123"
```
![alt text](https://github.com/cloud-ark/kubeprovenance/raw/master/docs/spechistory.png)
![alt text](https://github.com/cloud-ark/kubeprovenance/raw/master/docs/getdiff_databases.png)
Expand Down
12 changes: 7 additions & 5 deletions pkg/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,14 @@ func bisect(request *restful.Request, response *restful.Response) {

var provenanceInfo string
provenanceInfo = "Resource Name:" + resourceName + " Resource Kind:" + resourceKind
fmt.Println(provenanceInfo)

field := request.QueryParameter("field")
value := request.QueryParameter("value")
field1 := request.QueryParameter("field1")
value1 := request.QueryParameter("value1")

provenanceInfo = provenanceInfo + " Field:" + field + "Value: " + value + "\n"
field2 := request.QueryParameter("field2")
value2 := request.QueryParameter("value2")
provenanceInfo = provenanceInfo + " Field1:" + field1 + " Value1: " + value1 + "\n"
provenanceInfo = provenanceInfo + " Field2:" + field1 + " Value2: " + value1 + "\n"

fmt.Printf("ProvenanceInfo:%v", provenanceInfo)

Expand All @@ -232,7 +234,7 @@ func bisect(request *restful.Request, response *restful.Response) {
s := fmt.Sprintf("Could not find any provenance history for resource name: %s", resourceName)
response.Write([]byte(s))
} else {
response.Write([]byte("Version: " + intendedProvObj.ObjectFullHistory.Bisect(field, value)))
response.Write([]byte("Version: " + intendedProvObj.ObjectFullHistory.Bisect(field1, value1, field2, value2)))
response.Write([]byte(string("\n")))
}
}
Expand Down
160 changes: 137 additions & 23 deletions pkg/provenance/provenance.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type Event v1beta1.Event
//for example a postgres
type ObjectLineage map[int]Spec
type Spec struct {
AttributeToData map[string]string
AttributeToData map[string]interface{}
Version int
}

Expand Down Expand Up @@ -110,7 +110,7 @@ func NewProvenanceOfObject() *ProvenanceOfObject {

func NewSpec() *Spec {
var s Spec
s.AttributeToData = make(map[string]string)
s.AttributeToData = make(map[string]interface{})
return &s
}

Expand Down Expand Up @@ -170,26 +170,81 @@ func (o ObjectLineage) SpecHistory() string {
}
return strings.Join(specs, "\n")
}
func (o ObjectLineage) Bisect(field, value string) string {
s := make([]Spec, 0)
for _, spec := range o {
s = append(s, spec)
func (o ObjectLineage) Bisect(field1, value1, field2, value2 string) string {
s := make([]int, 0)
for _, value := range o {
s = append(s, value.Version)
}
sort.Slice(s, func(i, j int) bool {
return s[i].Version < s[i].Version
})
if len(s) == 1 {
sort.Ints(s)
//get all versions, sort by version, make string array of them
specs := make([]Spec, 0)
for _, version := range s {
specs = append(specs, o[version]) //cast Spec to String
}
noSpecFound := fmt.Sprintf("Bisect for field %s: %s, %s: %s was not successful. Custom resource never reached this state.", field1, value1, field2, value2)

if len(specs) == 1 {
//check
if s[0].AttributeToData[field] == value {
return strconv.Itoa(1)

u, ok1 := specs[0].AttributeToData[field1]
if !ok1 {
fmt.Printf("Field %s not found.\n", field1)
return noSpecFound
}
}
for _, v := range s {
if v.AttributeToData[field] == value {
return strconv.Itoa(v.Version)
p, ok2 := specs[0].AttributeToData[field2]
if !ok2 {
fmt.Printf("Field %s not found.\n", field2)
return noSpecFound
}
users, ok1 := p.([]string)
if !ok1 {
fmt.Printf("Type assertion failed. Underlying data is incorrect and is not a slice of strings: %s\n", u)
return noSpecFound
}
passwords, ok2 := u.([]string)
if !ok2 {
fmt.Printf("Type assertion failed. Underlying data is incorrect and is not a slice of strings: %s\n", p)
return noSpecFound
}

for i, v := range users {
if value1 == v && passwords[i] == value2 {
return "Version: " + strconv.Itoa(1)
}
}
} else { //there is more than one spec. More than one Event found in the log
for _, spec := range specs {
//check
u, ok1 := spec.AttributeToData[field1]
if !ok1 {
fmt.Printf("Field %s not found.\n", field1)
return noSpecFound
}
p, ok2 := spec.AttributeToData[field2]
if !ok2 {
fmt.Printf("Field %s not found.\n", field2)
return noSpecFound
}
users, ok1 := p.([]string)
if !ok1 {
fmt.Printf("Type assertion failed. Underlying data is incorrect and is not a slice of strings: %s\n", u)
return noSpecFound
}
passwords, ok2 := u.([]string)
if !ok2 {
fmt.Printf("Type assertion failed. Underlying data is incorrect and is not a slice of strings: %s\n", p)
return noSpecFound
}

for i1, v1 := range users {
if value1 == v1 && passwords[i1] == value2 {
return "Version: " + strconv.Itoa(spec.Version)
}
}
}
}
return strconv.Itoa(-1)

return noSpecFound
}

//TODO: add optional parameters to spechistory route in apiserver.go, and call this method.
Expand Down Expand Up @@ -359,6 +414,8 @@ func ParseRequestObject(objectProvenance *ProvenanceOfObject, requestObjBytes []
// fmt.Println(spec)
if ok {
fmt.Println("Successfully parsed")
} else {
fmt.Println("Unsuccessful parse")
}
newVersion := len(objectProvenance.ObjectFullHistory) + 1
newSpec := buildSpec(spec)
Expand All @@ -369,16 +426,73 @@ func ParseRequestObject(objectProvenance *ProvenanceOfObject, requestObjBytes []
func buildSpec(spec map[string]interface{}) Spec {
mySpec := *NewSpec()
for attribute, value := range spec {
bytes, err := json.MarshalIndent(value, "", " ")
if err != nil {
fmt.Println("Error could not marshal json: " + err.Error())
var isMap, isStringSlice, isString, isInt, isFloat bool
//note that I cannot do type assertions because the underlying data
//of the interface{} is not a map[string]string or an []slice
//so that means that every type assertion to
//value.([]map[string]string) fails, neither will []string. have to cast, store that data as desired
var mapSliceField []map[string]string
bytes, _ := json.MarshalIndent(value, "", " ")
if err := json.Unmarshal(bytes, &mapSliceField); err == nil {
isMap = true
}
var stringSliceField []string
if err := json.Unmarshal(bytes, &stringSliceField); err == nil {
isStringSlice = true
}
var plainStringField string
if err := json.Unmarshal(bytes, &plainStringField); err == nil {
isString = true
}
var floatField float64
if err := json.Unmarshal(bytes, &floatField); err == nil {
isFloat = true
}
var intField int
if err := json.Unmarshal(bytes, &intField); err == nil {
isInt = true
}
switch {
case isMap:
//we don't know the keys and don't know the data
//could be this for example:
//usernames = [daniel, steve, jenny]
//passwords = [22d732, 4343e2, 434343b]
attributeToSlices := make(map[string][]string, 0)
//build this and then i will loop through and add this to the spec
for _, mapl := range mapSliceField {

for key, data := range mapl {
slice, ok := attributeToSlices[key]
if ok {
slice = append(slice, data)
attributeToSlices[key] = slice
} else { // first time seeing this key
slice := make([]string, 0)
attributeToSlices[key] = slice
}
}
}
//now add to the attributes
for key, value := range attributeToSlices {
mySpec.AttributeToData[key] = value
}

case isStringSlice:
mySpec.AttributeToData[attribute] = stringSliceField
case isString:
mySpec.AttributeToData[attribute] = plainStringField
case isFloat:
mySpec.AttributeToData[attribute] = floatField
case isInt:
mySpec.AttributeToData[attribute] = intField
default:
fmt.Println(value)
fmt.Println("Error with the spec data. not a map slice, float, int, string slice, or string.")
}
attributeData := string(bytes)
mySpec.AttributeToData[attribute] = attributeData
}
return mySpec
}

func printMaps() {
fmt.Println("Printing kindVersionMap")
for key, value := range kindVersionMap {
Expand Down

0 comments on commit f2c1270

Please sign in to comment.