Skip to content

Commit 1cea2ad

Browse files
authored
Update rbac commands (#26)
This PR adds fix for different APIs added to the server for role based access control
1 parent e638b2c commit 1cea2ad

File tree

3 files changed

+331
-81
lines changed

3 files changed

+331
-81
lines changed

cmd/role.go

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
// Copyright (c) 2023 Cloudnatively Services Pvt Ltd
2+
//
3+
// This program is free software: you can redistribute it and/or modify
4+
// it under the terms of the GNU Affero General Public License as published by
5+
// the Free Software Foundation, either version 3 of the License, or
6+
// (at your option) any later version.
7+
//
8+
// This program is distributed in the hope that it will be useful
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
// GNU Affero General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU Affero General Public License
14+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
package cmd
17+
18+
import (
19+
"bytes"
20+
"encoding/json"
21+
"fmt"
22+
"io"
23+
"os"
24+
"pb/pkg/model/role"
25+
"strings"
26+
"sync"
27+
28+
tea "github.com/charmbracelet/bubbletea"
29+
"github.com/charmbracelet/lipgloss"
30+
"github.com/spf13/cobra"
31+
)
32+
33+
type RoleResource struct {
34+
Stream string `json:"stream,omitempty"`
35+
Tag string `json:"tag,omitempty"`
36+
}
37+
38+
type RoleData struct {
39+
Privilege string `json:"privilege"`
40+
Resource *RoleResource `json:"resource,omitempty"`
41+
}
42+
43+
func (user *RoleData) Render() string {
44+
var s strings.Builder
45+
s.WriteString(standardStyle.Render("Privilege: "))
46+
s.WriteString(standardStyleAlt.Render(user.Privilege))
47+
s.WriteString("\n")
48+
if user.Resource != nil {
49+
if user.Resource.Stream != "" {
50+
s.WriteString(standardStyle.Render("Stream: "))
51+
s.WriteString(standardStyleAlt.Render(user.Resource.Stream))
52+
s.WriteString("\n")
53+
}
54+
if user.Resource.Tag != "" {
55+
s.WriteString(standardStyle.Render("Tag: "))
56+
s.WriteString(standardStyleAlt.Render(user.Resource.Tag))
57+
s.WriteString("\n")
58+
}
59+
}
60+
61+
return s.String()
62+
}
63+
64+
var AddRoleCmd = &cobra.Command{
65+
Use: "upsert role-name",
66+
Example: " pb role upsert ingestors",
67+
Short: "Add a new role",
68+
Args: cobra.ExactArgs(1),
69+
RunE: func(cmd *cobra.Command, args []string) error {
70+
name := args[0]
71+
72+
_m, err := tea.NewProgram(role.New()).Run()
73+
if err != nil {
74+
fmt.Printf("Alas, there's been an error: %v", err)
75+
os.Exit(1)
76+
}
77+
m := _m.(role.Model)
78+
79+
privilege := m.Selection.Value()
80+
stream := m.Stream.Value()
81+
tag := m.Tag.Value()
82+
83+
if !m.Success {
84+
fmt.Println("aborted by user")
85+
return nil
86+
}
87+
88+
var putBody io.Reader
89+
90+
// set role
91+
if privilege != "none" {
92+
roleData := RoleData{
93+
Privilege: privilege,
94+
}
95+
switch privilege {
96+
case "writer":
97+
roleData.Resource = &RoleResource{
98+
Stream: stream,
99+
}
100+
case "reader":
101+
roleData.Resource = &RoleResource{
102+
Stream: stream,
103+
}
104+
if tag != "" {
105+
roleData.Resource.Tag = tag
106+
}
107+
}
108+
roleDataJSON, _ := json.Marshal([]RoleData{roleData})
109+
putBody = bytes.NewBuffer(roleDataJSON)
110+
}
111+
112+
client := DefaultClient()
113+
req, err := client.NewRequest("PUT", "role/"+name, putBody)
114+
if err != nil {
115+
return err
116+
}
117+
118+
resp, err := client.client.Do(req)
119+
if err != nil {
120+
return err
121+
}
122+
123+
bytes, err := io.ReadAll(resp.Body)
124+
if err != nil {
125+
return err
126+
}
127+
body := string(bytes)
128+
defer resp.Body.Close()
129+
130+
if resp.StatusCode == 200 {
131+
fmt.Printf("Added role %s", name)
132+
} else {
133+
fmt.Printf("Request Failed\nStatus Code: %s\nResponse: %s\n", resp.Status, body)
134+
}
135+
136+
return nil
137+
},
138+
}
139+
140+
var RemoveRoleCmd = &cobra.Command{
141+
Use: "remove role-name",
142+
Aliases: []string{"rm"},
143+
Example: " pb role remove ingestor",
144+
Short: "Delete a role",
145+
Args: cobra.ExactArgs(1),
146+
RunE: func(cmd *cobra.Command, args []string) error {
147+
name := args[0]
148+
client := DefaultClient()
149+
req, err := client.NewRequest("DELETE", "role/"+name, nil)
150+
if err != nil {
151+
return err
152+
}
153+
154+
resp, err := client.client.Do(req)
155+
if err != nil {
156+
return err
157+
}
158+
159+
if resp.StatusCode == 200 {
160+
fmt.Printf("Removed role %s\n", styleBold.Render(name))
161+
} else {
162+
bytes, err := io.ReadAll(resp.Body)
163+
if err != nil {
164+
return err
165+
}
166+
body := string(bytes)
167+
defer resp.Body.Close()
168+
169+
fmt.Printf("Request Failed\nStatus Code: %s\nResponse: %s\n", resp.Status, body)
170+
}
171+
172+
return nil
173+
},
174+
}
175+
176+
var ListRoleCmd = &cobra.Command{
177+
Use: "list",
178+
Short: "List all roles",
179+
Example: " pb role list",
180+
RunE: func(cmd *cobra.Command, args []string) error {
181+
var roles []string
182+
client := DefaultClient()
183+
err := fetchRoles(&client, &roles)
184+
if err != nil {
185+
return err
186+
}
187+
188+
roleResponses := make([]struct {
189+
data []RoleData
190+
err error
191+
}, len(roles))
192+
193+
wsg := sync.WaitGroup{}
194+
for idx, role := range roles {
195+
wsg.Add(1)
196+
out := &roleResponses[idx]
197+
role := role
198+
client := &client
199+
go func() {
200+
out.data, out.err = fetchSpecificRole(client, role)
201+
wsg.Done()
202+
}()
203+
}
204+
205+
wsg.Wait()
206+
fmt.Println()
207+
for idx, roleName := range roles {
208+
fetchRes := roleResponses[idx]
209+
fmt.Print("• ")
210+
fmt.Println(standardStyleBold.Bold(true).Render(roleName))
211+
if fetchRes.err == nil {
212+
for _, role := range fetchRes.data {
213+
fmt.Println(lipgloss.NewStyle().PaddingLeft(3).Render(role.Render()))
214+
}
215+
} else {
216+
fmt.Println(fetchRes.err)
217+
}
218+
}
219+
220+
return nil
221+
},
222+
}
223+
224+
func fetchRoles(client *HTTPClient, data *[]string) error {
225+
req, err := client.NewRequest("GET", "role", nil)
226+
if err != nil {
227+
return err
228+
}
229+
230+
resp, err := client.client.Do(req)
231+
if err != nil {
232+
return err
233+
}
234+
235+
bytes, err := io.ReadAll(resp.Body)
236+
if err != nil {
237+
return err
238+
}
239+
defer resp.Body.Close()
240+
241+
if resp.StatusCode == 200 {
242+
err = json.Unmarshal(bytes, data)
243+
if err != nil {
244+
return err
245+
}
246+
} else {
247+
body := string(bytes)
248+
return fmt.Errorf("request failed\nstatus code: %s\nresponse: %s", resp.Status, body)
249+
}
250+
251+
return nil
252+
}
253+
254+
func fetchSpecificRole(client *HTTPClient, role string) (res []RoleData, err error) {
255+
req, err := client.NewRequest("GET", fmt.Sprintf("role/%s", role), nil)
256+
if err != nil {
257+
return
258+
}
259+
260+
resp, err := client.client.Do(req)
261+
if err != nil {
262+
return
263+
}
264+
265+
bytes, err := io.ReadAll(resp.Body)
266+
if err != nil {
267+
return
268+
}
269+
defer resp.Body.Close()
270+
271+
if resp.StatusCode == 200 {
272+
err = json.Unmarshal(bytes, &res)
273+
if err != nil {
274+
return
275+
}
276+
} else {
277+
body := string(bytes)
278+
err = fmt.Errorf("request failed\nstatus code: %s\nresponse: %s", resp.Status, body)
279+
return
280+
}
281+
282+
return
283+
}

0 commit comments

Comments
 (0)