-
Notifications
You must be signed in to change notification settings - Fork 29
/
service_user.go
174 lines (148 loc) · 5.46 KB
/
service_user.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
package aiven
import (
"context"
"encoding/json"
"errors"
"fmt"
"reflect"
"time"
)
const (
UpdateOperationResetCredentials = "reset-credentials"
UpdateOperationSetAccessControl = "set-access-control"
)
type (
// ServiceUser is the representation of a Service User in the Aiven API.
ServiceUser struct {
Username string `json:"username"`
Password string `json:"password"`
Type string `json:"type"`
AccessCert string `json:"access_cert"`
AccessKey string `json:"access_key"`
AccessCertNotValidAfterTime *time.Time `json:"access_cert_not_valid_after_time"`
AccessControl AccessControl `json:"access_control,omitempty"`
}
AccessControl struct {
M3Group *string `json:"m3_group"`
RedisACLCategories []string `json:"redis_acl_categories"`
RedisACLCommands []string `json:"redis_acl_commands"`
RedisACLKeys []string `json:"redis_acl_keys"`
RedisACLChannels []string `json:"redis_acl_channels"`
PostgresAllowReplication *bool `json:"pg_allow_replication"`
}
// ServiceUsersHandler is the client that interacts with the ServiceUsers
// endpoints.
ServiceUsersHandler struct {
client *Client
}
// CreateServiceUserRequest are the parameters required to create a
// ServiceUser.
CreateServiceUserRequest struct {
Username string `json:"username"`
Authentication *string `json:"authentication,omitempty"`
AccessControl *AccessControl `json:"access_control,omitempty"`
}
// ModifyServiceUserRequest params required to modify a ServiceUser
ModifyServiceUserRequest struct {
Operation *string `json:"operation"`
Authentication *string `json:"authentication,omitempty"`
NewPassword *string `json:"new_password,omitempty"`
AccessControl *AccessControl `json:"access_control,omitempty"`
}
// ServiceUserResponse represents the response after creating a ServiceUser.
ServiceUserResponse struct {
APIResponse
User *ServiceUser `json:"user"`
}
)
// MarshalJSON implements a custom marshalling process for AccessControl where only null fields are omitted
func (ac AccessControl) MarshalJSON() ([]byte, error) {
out := make(map[string]interface{})
fields := reflect.TypeOf(ac)
values := reflect.ValueOf(ac)
for i := 0; i < fields.NumField(); i++ {
field := fields.Field(i)
value := values.Field(i)
switch value.Kind() {
case reflect.Pointer, reflect.Slice: // *string, *bool, []string
if !value.IsNil() {
jsonName := field.Tag.Get("json")
out[jsonName] = value.Interface()
}
}
}
return json.Marshal(out)
}
// Create creates the given User on Aiven.
func (h *ServiceUsersHandler) Create(ctx context.Context, project, service string, req CreateServiceUserRequest) (*ServiceUser, error) {
path := buildPath("project", project, "service", service, "user")
bts, err := h.client.doPostRequest(ctx, path, req)
if err != nil {
return nil, err
}
var r ServiceUserResponse
errR := checkAPIResponse(bts, &r)
return r.User, errR
}
// List Service Users for given service in Aiven.
func (h *ServiceUsersHandler) List(ctx context.Context, project, serviceName string) ([]*ServiceUser, error) {
// Aiven API does not provide list operation for service users, need to get them via service info instead
service, err := h.client.Services.Get(ctx, project, serviceName)
if err != nil {
return nil, err
}
return service.Users, nil
}
// Get specific Service User in Aiven.
func (h *ServiceUsersHandler) Get(ctx context.Context, project, serviceName, username string) (*ServiceUser, error) {
// Aiven API does not provide get operation for service users, need to get them via list instead
users, err := h.List(ctx, project, serviceName)
if err != nil {
return nil, err
}
for _, user := range users {
if user.Username == username {
return user, nil
}
}
err = Error{Message: fmt.Sprintf("Service user with username %v not found", username), Status: 404}
return nil, err
}
// Update modifies the given Service User in Aiven.
func (h *ServiceUsersHandler) Update(ctx context.Context, project, service, username string, update ModifyServiceUserRequest) (*ServiceUser, error) {
var DefaultOperation = UpdateOperationResetCredentials
if update.Operation == nil {
update.Operation = &DefaultOperation
}
if update.AccessControl != nil && *update.Operation != UpdateOperationSetAccessControl {
return nil, errors.New("wrong operation for updating access control")
}
if (update.NewPassword != nil || update.Authentication != nil) && *update.Operation != UpdateOperationResetCredentials {
return nil, errors.New("wrong operation for updating credentials")
}
path := buildPath("project", project, "service", service, "user", username)
svc, err := h.client.doPutRequest(ctx, path, update)
if err != nil {
return nil, err
}
var r ServiceResponse
errR := checkAPIResponse(svc, &r)
if errR == nil {
for _, user := range r.Service.Users {
if user.Username == username {
return user, nil
}
}
return nil, errors.New("user not found")
}
return nil, errR
}
// Delete deletes the given Service User in Aiven.
func (h *ServiceUsersHandler) Delete(ctx context.Context, project, service, user string) error {
path := buildPath("project", project, "service", service, "user", user)
bts, err := h.client.doDeleteRequest(ctx, path, nil)
if err != nil {
return err
}
return checkAPIResponse(bts, nil)
}