-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathclient.go
206 lines (165 loc) · 4.6 KB
/
client.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
package xenstore
import (
"bytes"
"strconv"
"strings"
)
// Client is a wrapper which allows easier communication with XenStore by providing
// methods which allow performing normal XenStore functions with minimal effort.
type Client struct {
transport Transport
router *Router
stopError error
}
// NewUnixSocketClient creates a new Client which will be connected to an underlying
// UnixSocket.
func NewUnixSocketClient(path string) (*Client, error) {
t, err := NewUnixSocketTransport(path)
if err != nil {
return nil, err
}
return NewClient(t), nil
}
// NewXenBusClient creates a new Client which will be connected to an underlying
// XenBus device.
func NewXenBusClient(path string) (*Client, error) {
t, err := NewXenBusTransport(path)
if err != nil {
return nil, err
}
return NewClient(t), nil
}
// NewClient creates a new connected Client and starts the internal Router so
// that packets can be sent and received correctly by the Client.
func NewClient(t Transport) *Client {
c := &Client{
transport: t,
router: NewRouter(t),
}
// Run router in separate goroutine
go func() {
c.stopError = c.router.Start()
}()
return c
}
// Close stops the underlying Router and closes the Transport.
func (c *Client) Close() error {
c.router.Stop()
return c.transport.Close()
}
func (c *Client) Error() error {
return c.stopError
}
// submitBytes submits a Packet to XenStore and reads a Packet in reply. The response packet
// is checked for errors which are returned from XenStore as strings.
//
// This method blocks until the reply packet is received.
func (c *Client) submitBytes(op xenStoreOperation, payload []byte, txid uint32) (*Packet, error) {
p, err := NewPacket(op, []byte(payload), 0x0)
if err != nil {
return nil, err
}
ch, err := c.router.Send(p)
if err != nil {
return nil, err
}
rsp := <-ch
if rsp.Header.Op == XsError {
trimmed := strings.Trim(string(rsp.Payload), "\x00")
return nil, Error(trimmed)
}
return rsp, nil
}
// List lists the descendants of path.
func (c *Client) List(path string) ([]string, error) {
p, err := c.submitBytes(XsDirectory, []byte(path), 0x0)
if err != nil {
return []string{}, err
}
// Contents are delimited by NUL bytes
return strings.Split(p.payloadString(), "\x00"), nil
}
// Read reads the contents of path from XenStore.
func (c *Client) Read(path string) (string, error) {
p, err := c.submitBytes(XsRead, []byte(path), 0x0)
if err != nil {
return "", err
}
return p.payloadString(), nil
}
// Remove removes a path from XenStore recursively
func (c *Client) Remove(path string) (string, error) {
p, err := c.submitBytes(XsRm, []byte(path), 0x0)
if err != nil {
return "", err
}
return p.payloadString(), nil
}
// Write value to XenStore at path.
func (c *Client) Write(path, value string) (string, error) {
buf := bytes.NewBufferString(path)
buf.WriteByte(NUL)
buf.WriteString(value)
p, err := c.submitBytes(XsWrite, buf.Bytes(), 0x0)
if err != nil {
return "", err
}
return p.payloadString(), nil
}
// GetPermissions returns the currently stored permissions for a XenStore path.
func (c *Client) GetPermissions(path string) (string, error) {
p, err := c.submitBytes(XsGetPermissions, []byte(path), 0x0)
if err != nil {
return "", err
}
return p.payloadString(), nil
}
// SetPermissions sets the permissions for a path in XenStore.
func (c *Client) SetPermissions(path string, perms []string) (string, error) {
buf := bytes.NewBufferString(path)
for _, perm := range perms {
buf.WriteByte(NUL)
buf.WriteString(perm)
}
p, err := c.submitBytes(XsSetPermissions, buf.Bytes(), 0x0)
if err != nil {
return "", err
}
return p.payloadString(), nil
}
// GetDomainPath
func (c *Client) GetDomainPath(domid int) (string, error) {
s := strconv.Itoa(domid)
p, err := c.submitBytes(XsGetDomainPath, []byte(s), 0x0)
if err != nil {
return "", err
}
return p.payloadString(), nil
}
// Watch places a watch on a particular XenStore path
func (c *Client) Watch(path, token string) (chan *Packet, error) {
buf := bytes.NewBufferString(path)
buf.WriteByte(NUL)
buf.WriteString(token)
p, err := NewPacket(XsWatch, buf.Bytes(), 0x0)
if err != nil {
return nil, err
}
return c.router.Send(p)
}
// UnWatch removes a previously-set watch on a XenStore path.
func (c *Client) UnWatch(path, token string) error {
buf := bytes.NewBufferString(path)
buf.WriteByte(NUL)
buf.WriteString(token)
p, err := c.submitBytes(XsUnWatch, buf.Bytes(), 0x0)
if err != nil {
return err
}
// Ensure the returned packet was not an error
if err := p.Check(); err != nil {
return err
}
c.router.removeWatchChannel(token)
return nil
}