Skip to content

Commit

Permalink
Merge pull request #30 from mavenugo/unmarshal
Browse files Browse the repository at this point in the history
Unmarshalling support
  • Loading branch information
dave-tucker committed Nov 14, 2014
2 parents 504967c + 9d99294 commit 555a561
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 11 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*.o
*.a
*.so
*.swp

# Folders
_obj
Expand Down
103 changes: 95 additions & 8 deletions example/play_with_ovs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"fmt"
"os"
"reflect"

"github.com/socketplane/libovsdb"
)
Expand All @@ -12,20 +13,19 @@ import (

var quit chan bool
var update chan *libovsdb.TableUpdates
var cache map[string]map[string]libovsdb.Row

func play(ovs *libovsdb.OvsdbClient) {
ovs.MonitorAll("Open_vSwitch", "")
go processInput(ovs)
for {
select {
case currUpdate := <-update:
for table, tableUpdate := range currUpdate.Updates {
fmt.Println("Received Table update on : ", table)
if table == "Bridge" {
rows := tableUpdate.Rows
for uuid, row := range rows {
for uuid, row := range tableUpdate.Rows {
newRow := row.New
if newRow != nil {
name := newRow["name"].(string)
if _, ok := newRow.Fields["name"]; ok {
name := newRow.Fields["name"].(string)
if name == "stop" {
fmt.Println("Bridge stop detected : ", uuid)
quit <- true
Expand All @@ -39,15 +39,98 @@ func play(ovs *libovsdb.OvsdbClient) {

}

func createBridge(ovs *libovsdb.OvsdbClient, bridgeName string) {
namedUuid := "gopher"
// bridge row to insert
bridge := make(map[string]interface{})
bridge["name"] = bridgeName

// simple insert operation
insertOp := libovsdb.Operation{
Op: "insert",
Table: "Bridge",
Row: bridge,
UUIDName: namedUuid,
}

// Inserting a Bridge row in Bridge table requires mutating the open_vswitch table.
mutateUuid := []libovsdb.UUID{libovsdb.UUID{namedUuid}}
mutateSet, _ := libovsdb.NewOvsSet(mutateUuid)
mutation := libovsdb.NewMutation("bridges", "insert", mutateSet)
condition := libovsdb.NewCondition("_uuid", "==", libovsdb.UUID{getRootUuid()})

// simple mutate operation
mutateOp := libovsdb.Operation{
Op: "mutate",
Table: "Open_vSwitch",
Mutations: []interface{}{mutation},
Where: []interface{}{condition},
}

operations := []libovsdb.Operation{insertOp, mutateOp}
reply, _ := ovs.Transact("Open_vSwitch", operations...)

if len(reply) < len(operations) {
fmt.Println("Number of Replies should be atleast equal to number of Operations")
}
ok := true
for i, o := range reply {
if o.Error != "" && i < len(operations) {
fmt.Println("Transaction Failed due to an error :", o.Error, " details:", o.Details, " in ", operations[i])
ok = false
} else if o.Error != "" {
fmt.Println("Transaction Failed due to an error :", o.Error)
ok = false
}
}
if ok {
fmt.Println("Bridge Addition Successful : ", reply[0].UUID.GoUuid)
}
}

func processInput(ovs *libovsdb.OvsdbClient) {
for {
fmt.Printf("\n Enter a Bridge Name : ")
var bridgeName string
fmt.Scanf("%s", &bridgeName)
createBridge(ovs, bridgeName)
}
}

func getRootUuid() string {
for uuid, _ := range cache["Open_vSwitch"] {
return uuid
}
return ""
}

func populateCache(updates libovsdb.TableUpdates) {
for table, tableUpdate := range updates.Updates {
if _, ok := cache[table]; !ok {
cache[table] = make(map[string]libovsdb.Row)

}
for uuid, row := range tableUpdate.Rows {
empty := libovsdb.Row{}
if !reflect.DeepEqual(row.New, empty) {
cache[table][uuid] = row.New
} else {
delete(cache[table], uuid)
}
}
}
}

func main() {
quit = make(chan bool)
update = make(chan *libovsdb.TableUpdates)
cache = make(map[string]map[string]libovsdb.Row)

// By default libovsdb connects to 127.0.0.0:6400.
ovs, err := libovsdb.Connect("", 0)

// If you prefer to connect to OVS in a specific location :
//ovs, err := libovsdb.Connect("192.168.56.101", 6640)
// ovs, err := libovsdb.Connect("192.168.56.101", 6640)

if err != nil {
fmt.Println("Unable to Connect ", err)
Expand All @@ -56,7 +139,10 @@ func main() {
var notifier Notifier
ovs.Register(notifier)

fmt.Println(`Silly game of stopping this app when a Bridge with name "stop" is monitored`)
initial, _ := ovs.MonitorAll("Open_vSwitch", "")
populateCache(*initial)

fmt.Println(`Silly game of stopping this app when a Bridge with name "stop" is monitored !`)
go play(ovs)
<-quit
}
Expand All @@ -65,6 +151,7 @@ type Notifier struct {
}

func (n Notifier) Update(context interface{}, tableUpdates libovsdb.TableUpdates) {
populateCache(tableUpdates)
update <- &tableUpdates
}
func (n Notifier) Locked([]interface{}) {
Expand Down
13 changes: 13 additions & 0 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ func (o OvsMap) MarshalJSON() ([]byte, error) {
return json.Marshal(ovsMap)
}

func (o *OvsMap) UnmarshalJSON(b []byte) (err error) {
var oMap []interface{}
o.GoMap = make(map[interface{}]interface{})
if err := json.Unmarshal(b, &oMap); err == nil && len(oMap) > 1 {
innerSlice := oMap[1].([]interface{})
for _, val := range innerSlice {
f := val.([]interface{})
o.GoMap[f[0]] = f[1]
}
}
return err
}

// <map> notation requires special marshaling
func NewOvsMap(goMap interface{}) (*OvsMap, error) {
v := reflect.ValueOf(goMap)
Expand Down
36 changes: 33 additions & 3 deletions notation.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package libovsdb

import "encoding/json"

// Operation represents an operation according to RFC7047 section 5.2
type Operation struct {
Op string `json:"op"`
Expand Down Expand Up @@ -55,9 +57,9 @@ type TableUpdate struct {
}

type RowUpdate struct {
Uuid UUID `json:"-,omitempty"`
New map[string]interface{} `json:"new,omitempty"`
Old map[string]interface{} `json:"old,omitempty"`
Uuid UUID `json:"-,omitempty"`
New Row `json:"new,omitempty"`
Old Row `json:"old,omitempty"`
}

// OvsdbError is an OVS Error Condition
Expand Down Expand Up @@ -89,4 +91,32 @@ type OperationResult struct {
Rows []map[string]interface{} `json:"rows,omitempty"`
}

func ovsSliceToGoNotation(val interface{}) (interface{}, error) {
switch val.(type) {
case []interface{}:
sl := val.([]interface{})
bsliced, err := json.Marshal(sl)
if err != nil {
return nil, err
}

switch sl[0] {
case "uuid":
var uuid UUID
err = json.Unmarshal(bsliced, &uuid)
return uuid, err
case "set":
var oSet OvsSet
err = json.Unmarshal(bsliced, &oSet)
return oSet, err
case "map":
var oMap OvsMap
err = json.Unmarshal(bsliced, &oMap)
return oMap, err
}
return val, nil
}
return val, nil
}

// TODO : add Condition, Function, Mutation and Mutator notations
21 changes: 21 additions & 0 deletions row.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package libovsdb

import "encoding/json"

type Row struct {
Fields map[string]interface{}
}

func (r *Row) UnmarshalJSON(b []byte) (err error) {
r.Fields = make(map[string]interface{})
var raw map[string]interface{}
err = json.Unmarshal(b, &raw)
for key, val := range raw {
val, err = ovsSliceToGoNotation(val)
if err != nil {
return err
}
r.Fields[key] = val
}
return err
}
14 changes: 14 additions & 0 deletions set.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,17 @@ func (o OvsSet) MarshalJSON() ([]byte, error) {
oSet = append(oSet, o.GoSet)
return json.Marshal(oSet)
}

func (o *OvsSet) UnmarshalJSON(b []byte) (err error) {
var oSet []interface{}
if err = json.Unmarshal(b, &oSet); err == nil && len(oSet) > 1 {
innerSet := oSet[1].([]interface{})
for _, val := range innerSet {
goVal, err := ovsSliceToGoNotation(val)
if err == nil {
o.GoSet = append(o.GoSet, goVal)
}
}
}
return err
}

0 comments on commit 555a561

Please sign in to comment.