1// Copyright 2016 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package command
16
17import (
18	"fmt"
19	"os"
20	"strings"
21
22	v3 "github.com/coreos/etcd/clientv3"
23	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
24)
25
26type simplePrinter struct {
27	isHex     bool
28	valueOnly bool
29}
30
31func (s *simplePrinter) Del(resp v3.DeleteResponse) {
32	fmt.Println(resp.Deleted)
33	for _, kv := range resp.PrevKvs {
34		printKV(s.isHex, s.valueOnly, kv)
35	}
36}
37
38func (s *simplePrinter) Get(resp v3.GetResponse) {
39	for _, kv := range resp.Kvs {
40		printKV(s.isHex, s.valueOnly, kv)
41	}
42}
43
44func (s *simplePrinter) Put(r v3.PutResponse) {
45	fmt.Println("OK")
46	if r.PrevKv != nil {
47		printKV(s.isHex, s.valueOnly, r.PrevKv)
48	}
49}
50
51func (s *simplePrinter) Txn(resp v3.TxnResponse) {
52	if resp.Succeeded {
53		fmt.Println("SUCCESS")
54	} else {
55		fmt.Println("FAILURE")
56	}
57
58	for _, r := range resp.Responses {
59		fmt.Println("")
60		switch v := r.Response.(type) {
61		case *pb.ResponseOp_ResponseDeleteRange:
62			s.Del((v3.DeleteResponse)(*v.ResponseDeleteRange))
63		case *pb.ResponseOp_ResponsePut:
64			s.Put((v3.PutResponse)(*v.ResponsePut))
65		case *pb.ResponseOp_ResponseRange:
66			s.Get(((v3.GetResponse)(*v.ResponseRange)))
67		default:
68			fmt.Printf("unexpected response %+v\n", r)
69		}
70	}
71}
72
73func (s *simplePrinter) Watch(resp v3.WatchResponse) {
74	for _, e := range resp.Events {
75		fmt.Println(e.Type)
76		if e.PrevKv != nil {
77			printKV(s.isHex, s.valueOnly, e.PrevKv)
78		}
79		printKV(s.isHex, s.valueOnly, e.Kv)
80	}
81}
82
83func (s *simplePrinter) Grant(resp v3.LeaseGrantResponse) {
84	fmt.Printf("lease %016x granted with TTL(%ds)\n", resp.ID, resp.TTL)
85}
86
87func (p *simplePrinter) Revoke(id v3.LeaseID, r v3.LeaseRevokeResponse) {
88	fmt.Printf("lease %016x revoked\n", id)
89}
90
91func (p *simplePrinter) KeepAlive(resp v3.LeaseKeepAliveResponse) {
92	fmt.Printf("lease %016x keepalived with TTL(%d)\n", resp.ID, resp.TTL)
93}
94
95func (s *simplePrinter) TimeToLive(resp v3.LeaseTimeToLiveResponse, keys bool) {
96	txt := fmt.Sprintf("lease %016x granted with TTL(%ds), remaining(%ds)", resp.ID, resp.GrantedTTL, resp.TTL)
97	if keys {
98		ks := make([]string, len(resp.Keys))
99		for i := range resp.Keys {
100			ks[i] = string(resp.Keys[i])
101		}
102		txt += fmt.Sprintf(", attached keys(%v)", ks)
103	}
104	fmt.Println(txt)
105}
106
107func (s *simplePrinter) Alarm(resp v3.AlarmResponse) {
108	for _, e := range resp.Alarms {
109		fmt.Printf("%+v\n", e)
110	}
111}
112
113func (s *simplePrinter) MemberAdd(r v3.MemberAddResponse) {
114	fmt.Printf("Member %16x added to cluster %16x\n", r.Member.ID, r.Header.ClusterId)
115}
116
117func (s *simplePrinter) MemberRemove(id uint64, r v3.MemberRemoveResponse) {
118	fmt.Printf("Member %16x removed from cluster %16x\n", id, r.Header.ClusterId)
119}
120
121func (s *simplePrinter) MemberUpdate(id uint64, r v3.MemberUpdateResponse) {
122	fmt.Printf("Member %16x updated in cluster %16x\n", id, r.Header.ClusterId)
123}
124
125func (s *simplePrinter) MemberList(resp v3.MemberListResponse) {
126	_, rows := makeMemberListTable(resp)
127	for _, row := range rows {
128		fmt.Println(strings.Join(row, ", "))
129	}
130}
131
132func (s *simplePrinter) EndpointHealth(hs []epHealth) {
133	for _, h := range hs {
134		if h.Error == "" {
135			fmt.Fprintf(os.Stderr, "%s is healthy: successfully committed proposal: took = %v\n", h.Ep, h.Took)
136		} else {
137			fmt.Fprintf(os.Stderr, "%s is unhealthy: failed to commit proposal: %v\n", h.Ep, h.Error)
138		}
139	}
140}
141
142func (s *simplePrinter) EndpointStatus(statusList []epStatus) {
143	_, rows := makeEndpointStatusTable(statusList)
144	for _, row := range rows {
145		fmt.Println(strings.Join(row, ", "))
146	}
147}
148
149func (s *simplePrinter) DBStatus(ds dbstatus) {
150	_, rows := makeDBStatusTable(ds)
151	for _, row := range rows {
152		fmt.Println(strings.Join(row, ", "))
153	}
154}
155
156func (s *simplePrinter) RoleAdd(role string, r v3.AuthRoleAddResponse) {
157	fmt.Printf("Role %s created\n", role)
158}
159
160func (s *simplePrinter) RoleGet(role string, r v3.AuthRoleGetResponse) {
161	fmt.Printf("Role %s\n", role)
162	fmt.Println("KV Read:")
163
164	printRange := func(perm *v3.Permission) {
165		sKey := string(perm.Key)
166		sRangeEnd := string(perm.RangeEnd)
167		if strings.Compare(sRangeEnd, "\x00") != 0 {
168			fmt.Printf("\t[%s, %s)", sKey, sRangeEnd)
169		} else {
170			fmt.Printf("\t[%s, <open ended>", sKey)
171		}
172		if strings.Compare(v3.GetPrefixRangeEnd(sKey), sRangeEnd) == 0 {
173			fmt.Printf(" (prefix %s)", sKey)
174		}
175		fmt.Printf("\n")
176	}
177
178	for _, perm := range r.Perm {
179		if perm.PermType == v3.PermRead || perm.PermType == v3.PermReadWrite {
180			if len(perm.RangeEnd) == 0 {
181				fmt.Printf("\t%s\n", string(perm.Key))
182			} else {
183				printRange((*v3.Permission)(perm))
184			}
185		}
186	}
187	fmt.Println("KV Write:")
188	for _, perm := range r.Perm {
189		if perm.PermType == v3.PermWrite || perm.PermType == v3.PermReadWrite {
190			if len(perm.RangeEnd) == 0 {
191				fmt.Printf("\t%s\n", string(perm.Key))
192			} else {
193				printRange((*v3.Permission)(perm))
194			}
195		}
196	}
197}
198
199func (s *simplePrinter) RoleList(r v3.AuthRoleListResponse) {
200	for _, role := range r.Roles {
201		fmt.Printf("%s\n", role)
202	}
203}
204
205func (s *simplePrinter) RoleDelete(role string, r v3.AuthRoleDeleteResponse) {
206	fmt.Printf("Role %s deleted\n", role)
207}
208
209func (s *simplePrinter) RoleGrantPermission(role string, r v3.AuthRoleGrantPermissionResponse) {
210	fmt.Printf("Role %s updated\n", role)
211}
212
213func (s *simplePrinter) RoleRevokePermission(role string, key string, end string, r v3.AuthRoleRevokePermissionResponse) {
214	if len(end) == 0 {
215		fmt.Printf("Permission of key %s is revoked from role %s\n", key, role)
216		return
217	}
218	if strings.Compare(end, "\x00") != 0 {
219		fmt.Printf("Permission of range [%s, %s) is revoked from role %s\n", key, end, role)
220	} else {
221		fmt.Printf("Permission of range [%s, <open ended> is revoked from role %s\n", key, role)
222	}
223}
224
225func (s *simplePrinter) UserAdd(name string, r v3.AuthUserAddResponse) {
226	fmt.Printf("User %s created\n", name)
227}
228
229func (s *simplePrinter) UserGet(name string, r v3.AuthUserGetResponse) {
230	fmt.Printf("User: %s\n", name)
231	fmt.Printf("Roles:")
232	for _, role := range r.Roles {
233		fmt.Printf(" %s", role)
234	}
235	fmt.Printf("\n")
236}
237
238func (s *simplePrinter) UserChangePassword(v3.AuthUserChangePasswordResponse) {
239	fmt.Println("Password updated")
240}
241
242func (s *simplePrinter) UserGrantRole(user string, role string, r v3.AuthUserGrantRoleResponse) {
243	fmt.Printf("Role %s is granted to user %s\n", role, user)
244}
245
246func (s *simplePrinter) UserRevokeRole(user string, role string, r v3.AuthUserRevokeRoleResponse) {
247	fmt.Printf("Role %s is revoked from user %s\n", role, user)
248}
249
250func (s *simplePrinter) UserDelete(user string, r v3.AuthUserDeleteResponse) {
251	fmt.Printf("User %s deleted\n", user)
252}
253
254func (s *simplePrinter) UserList(r v3.AuthUserListResponse) {
255	for _, user := range r.Users {
256		fmt.Printf("%s\n", user)
257	}
258}
259