forked from Juniper/go-netconf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rpc.go
90 lines (76 loc) · 2.17 KB
/
rpc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package netconf
import (
"bytes"
"crypto/rand"
"encoding/xml"
"fmt"
"io"
)
type RPCMethod interface {
MarshalRPCMethod() string
}
// a raw RPC method is just a plain string
type RPCMethodRaw string
func (m RPCMethodRaw) MarshalRPCMethod() string {
return string(m)
}
func RPCMethodLock(target string) RPCMethod {
return RPCMethodRaw(fmt.Sprintf("<lock><target><%s/></target></lock>", target))
}
func MethodUnlock(target string) RPCMethod {
return RPCMethodRaw(fmt.Sprintf("<unlock><target><%s/></target></unlock>", target))
}
func MethodGetConfig(source string) RPCMethod {
return RPCMethodRaw(fmt.Sprintf("<get-config><source><%s/></source></get-config>", source))
}
// a message to send to the remote
type RPCMessage struct {
ID string
Methods []RPCMethod
}
func NewRPCMessage(methods []RPCMethod) *RPCMessage {
return &RPCMessage{
ID: rpcUUID(),
Methods: methods,
}
}
func (m *RPCMessage) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
var buf bytes.Buffer
for _, method := range m.Methods {
buf.WriteString(method.MarshalRPCMethod())
}
data := struct {
ID string `xml:"message-id,attr"`
Methods []byte `xml:",innerxml"`
}{m.ID, buf.Bytes()}
start.Name.Local = "rpc"
return e.EncodeElement(data, start)
}
// the remote's response to valid RPC messages
type RPCReply struct {
XMLName xml.Name `xml:"rpc-reply"`
Errors []RPCError `xml:"rpc-error,omitempty"`
Data string `xml:",innerxml"`
Ok bool `xml:",omitempty"`
RawReply string `xml:"-"`
}
// an error returned over the course of RPC communication
type RPCError struct {
Type string `xml:"error-type"`
Tag string `xml:"error-tag"`
Severity string `xml:"error-severity"`
Path string `xml:"error-path"`
Message string `xml:"error-message"`
Info string `xml:",innerxml"`
}
func (re *RPCError) Error() string {
return fmt.Sprintf("netconf rpc [%s] '%s'", re.Severity, re.Message)
}
// construct a simple UUID for rpc messages
func rpcUUID() string {
b := make([]byte, 16)
io.ReadFull(rand.Reader, b)
b[6] = (b[6] & 0x0f) | 0x40
b[8] = (b[8] & 0x3f) | 0x80
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}