Skip to content

Commit 7d2b41d

Browse files
authored
[Feature] Extend Debug Package (#1871)
1 parent c87e7dc commit 7d2b41d

File tree

18 files changed

+378
-146
lines changed

18 files changed

+378
-146
lines changed

chart/kube-arangodb-arm64/templates/deployment-operator/role.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ rules:
5151
- apiGroups: [""]
5252
resources: ["pods/log"]
5353
verbs: ["get", "list"]
54+
- apiGroups: [""]
55+
resources: ["pods/exec"]
56+
verbs: ["create"]
5457
{{- end }}
5558
{{- if .Values.rbac.extensions.monitoring }}
5659
- apiGroups: ["monitoring.coreos.com"]

chart/kube-arangodb-enterprise-arm64/templates/deployment-operator/role.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ rules:
5151
- apiGroups: [""]
5252
resources: ["pods/log"]
5353
verbs: ["get", "list"]
54+
- apiGroups: [""]
55+
resources: ["pods/exec"]
56+
verbs: ["create"]
5457
{{- end }}
5558
{{- if .Values.rbac.extensions.monitoring }}
5659
- apiGroups: ["monitoring.coreos.com"]

chart/kube-arangodb-enterprise/templates/deployment-operator/role.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ rules:
5151
- apiGroups: [""]
5252
resources: ["pods/log"]
5353
verbs: ["get", "list"]
54+
- apiGroups: [""]
55+
resources: ["pods/exec"]
56+
verbs: ["create"]
5457
{{- end }}
5558
{{- if .Values.rbac.extensions.monitoring }}
5659
- apiGroups: ["monitoring.coreos.com"]

chart/kube-arangodb/templates/deployment-operator/role.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ rules:
5151
- apiGroups: [""]
5252
resources: ["pods/log"]
5353
verbs: ["get", "list"]
54+
- apiGroups: [""]
55+
resources: ["pods/exec"]
56+
verbs: ["create"]
5457
{{- end }}
5558
{{- if .Values.rbac.extensions.monitoring }}
5659
- apiGroups: ["monitoring.coreos.com"]

cmd/admin.go

Lines changed: 166 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ import (
4343

4444
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
4545
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
46+
"github.com/arangodb/kube-arangodb/pkg/util"
47+
"github.com/arangodb/kube-arangodb/pkg/util/cli"
4648
"github.com/arangodb/kube-arangodb/pkg/util/constants"
4749
"github.com/arangodb/kube-arangodb/pkg/util/errors"
4850
"github.com/arangodb/kube-arangodb/pkg/util/globals"
@@ -51,76 +53,149 @@ import (
5153
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
5254
)
5355

54-
const ArgDeploymentName = "deployment-name"
56+
const (
57+
ArgDeploymentName = "deployment-name"
58+
ArgMemberName = "member-name"
59+
ArgAcceptedCode = "accepted-code"
60+
)
5561

5662
func init() {
57-
var deploymentName string
58-
5963
cmdMain.AddCommand(cmdAdmin)
60-
cmdAdmin.AddCommand(cmdAgency)
64+
cmdAdmin.AddCommand(cmdAdminAgency)
65+
cmdAdmin.AddCommand(cmdAdminMember)
6166

62-
cmdAgency.AddCommand(cmdAgencyDump)
63-
cmdAgencyDump.Flags().StringVarP(&deploymentName, ArgDeploymentName, "d", "",
67+
cmdAdminAgency.AddCommand(cmdAdminAgencyDump)
68+
cmdAdminAgencyDump.Flags().StringP(ArgDeploymentName, "d", "",
6469
"necessary when more than one deployment exist within on namespace")
6570

66-
cmdAgency.AddCommand(cmdAgencyState)
67-
cmdAgencyState.Flags().StringVarP(&deploymentName, ArgDeploymentName, "d", "",
71+
cmdAdminAgency.AddCommand(cmdAdminAgencyState)
72+
cmdAdminAgencyState.Flags().StringP(ArgDeploymentName, "d", "",
6873
"necessary when more than one deployment exist within on namespace")
74+
75+
cmdAdminMember.AddCommand(cmdAdminMemberRequest)
76+
cmdAdminMemberRequest.AddCommand(cmdAdminMemberRequestGet)
77+
cmdAdminMemberRequestGet.Flags().StringP(ArgDeploymentName, "d", "",
78+
"necessary when more than one deployment exist within on namespace")
79+
cmdAdminMemberRequestGet.Flags().StringP(ArgMemberName, "m", "",
80+
"name of the member for the dump")
81+
cmdAdminMemberRequestGet.Flags().IntP(ArgAcceptedCode, "c", 200,
82+
"accepted command code")
6983
}
7084

7185
var cmdAdmin = &cobra.Command{
7286
Use: "admin",
7387
Short: "Administration operations",
74-
Run: adminShowUsage,
88+
RunE: cli.Usage,
7589
}
7690

77-
var cmdAgency = &cobra.Command{
91+
var cmdAdminMember = &cobra.Command{
92+
Use: "member",
93+
Short: "Member operations",
94+
RunE: cli.Usage,
95+
}
96+
97+
var cmdAdminMemberRequest = &cobra.Command{
98+
Use: "request",
99+
Short: "Runs http request over member and returns object",
100+
RunE: cli.Usage,
101+
}
102+
103+
var cmdAdminMemberRequestGet = &cobra.Command{
104+
Use: "get",
105+
Short: "GET Request",
106+
RunE: cmdGetAdminMemberRequestGetE,
107+
}
108+
109+
var cmdAdminAgency = &cobra.Command{
78110
Use: "agency",
79111
Short: "Agency operations",
80-
Run: agencyShowUsage,
112+
RunE: cli.Usage,
81113
}
82114

83-
var cmdAgencyDump = &cobra.Command{
115+
var cmdAdminAgencyDump = &cobra.Command{
84116
Use: "dump",
85117
Short: "Get agency dump",
86-
Long: "It prints the agency history on the stdout",
87-
Run: cmdGetAgencyDump,
118+
Long: "Prints the agency history on the stdout",
119+
RunE: cmdAdminGetAgencyDumpE,
88120
}
89121

90-
var cmdAgencyState = &cobra.Command{
122+
var cmdAdminAgencyState = &cobra.Command{
91123
Use: "state",
92124
Short: "Get agency state",
93-
Long: "It prints the agency current state on the stdout",
94-
Run: cmdGetAgencyState,
125+
Long: "Prints the agency current state on the stdout",
126+
RunE: cmdAdminGetAgencyStateE,
95127
}
96128

97-
func agencyShowUsage(cmd *cobra.Command, _ []string) {
98-
cmd.Usage()
99-
}
129+
func cmdGetAdminMemberRequestGetE(cmd *cobra.Command, args []string) error {
130+
deploymentName, err := cmd.Flags().GetString(ArgDeploymentName)
131+
if err != nil {
132+
return err
133+
}
134+
memberName, err := cmd.Flags().GetString(ArgMemberName)
135+
if err != nil {
136+
return err
137+
}
138+
acceptedCode, err := cmd.Flags().GetInt(ArgAcceptedCode)
139+
if err != nil {
140+
return err
141+
}
142+
ctx := getInterruptionContext()
143+
d, certCA, auth, err := getDeploymentAndCredentials(ctx, deploymentName)
144+
if err != nil {
145+
logger.Err(err).Error("failed to create basic data for the connection")
146+
return err
147+
}
148+
149+
m, g, ok := d.Status.Members.ElementByID(memberName)
150+
if !ok {
151+
err := errors.Errorf("Unable to find member with id %s", memberName)
152+
logger.Err(err).Error("Unable to find member")
153+
return err
154+
}
155+
156+
dnsName := k8sutil.CreatePodDNSName(d.GetObjectMeta(), g.AsRole(), m.ID)
157+
endpoint := getArangoEndpoint(d.GetAcceptedSpec().IsSecure(), dnsName)
158+
conn := createClient([]string{endpoint}, certCA, auth, connection.ApplicationJSON)
159+
body, err := sendStreamRequest(ctx, conn, goHttp.MethodGet, nil, acceptedCode, args...)
160+
if body != nil {
161+
defer body.Close()
162+
}
163+
if err != nil {
164+
logger.Err(err).Error("can not get dump")
165+
return err
166+
}
100167

101-
func adminShowUsage(cmd *cobra.Command, _ []string) {
102-
cmd.Usage()
168+
// Print and receive parallely.
169+
_, err = io.Copy(os.Stdout, body)
170+
return err
103171
}
104172

105-
func cmdGetAgencyState(cmd *cobra.Command, _ []string) {
106-
deploymentName, _ := cmd.Flags().GetString(ArgDeploymentName)
173+
func cmdAdminGetAgencyStateE(cmd *cobra.Command, _ []string) error {
174+
deploymentName, err := cmd.Flags().GetString(ArgDeploymentName)
175+
if err != nil {
176+
return err
177+
}
107178
ctx := getInterruptionContext()
108179
d, certCA, auth, err := getDeploymentAndCredentials(ctx, deploymentName)
109180
if err != nil {
110-
logger.Err(err).Fatal("failed to create basic data for the connection")
181+
logger.Err(err).Error("failed to create basic data for the connection")
182+
return err
111183
}
112184

113185
if d.GetAcceptedSpec().GetMode() != api.DeploymentModeCluster {
114-
logger.Fatal("agency state does not work for the \"%s\" deployment \"%s\"", d.GetAcceptedSpec().GetMode(),
186+
err = errors.Errorf("agency state does not work for the \"%s\" deployment \"%s\"", d.GetAcceptedSpec().GetMode(),
115187
d.GetName())
188+
logger.Err(err).Error("Invalid deployment type")
189+
return err
116190
}
117191

118192
dnsName := k8sutil.CreatePodDNSName(d.GetObjectMeta(), api.ServerGroupAgents.AsRole(), d.Status.Members.Agents[0].ID)
119193
endpoint := getArangoEndpoint(d.GetAcceptedSpec().IsSecure(), dnsName)
120194
conn := createClient([]string{endpoint}, certCA, auth, connection.ApplicationJSON)
121195
leaderID, err := getAgencyLeader(ctx, conn)
122196
if err != nil {
123-
logger.Err(err).Fatal("failed to get leader ID")
197+
logger.Err(err).Error("failed to get leader ID")
198+
return err
124199
}
125200

126201
dnsLeaderName := k8sutil.CreatePodDNSName(d.GetObjectMeta(), api.ServerGroupAgents.AsRole(), leaderID)
@@ -131,24 +206,32 @@ func cmdGetAgencyState(cmd *cobra.Command, _ []string) {
131206
defer body.Close()
132207
}
133208
if err != nil {
134-
logger.Err(err).Fatal("can not get state of the agency")
209+
logger.Err(err).Error("can not get state of the agency")
210+
return err
135211
}
136212

137-
// Print and receive parallelly.
138-
io.Copy(os.Stdout, body)
213+
// Print and receive parallely.
214+
_, err = io.Copy(os.Stdout, body)
215+
return err
139216
}
140217

141-
func cmdGetAgencyDump(cmd *cobra.Command, _ []string) {
142-
deploymentName, _ := cmd.Flags().GetString(ArgDeploymentName)
218+
func cmdAdminGetAgencyDumpE(cmd *cobra.Command, _ []string) error {
219+
deploymentName, err := cmd.Flags().GetString(ArgDeploymentName)
220+
if err != nil {
221+
return err
222+
}
143223
ctx := getInterruptionContext()
144224
d, certCA, auth, err := getDeploymentAndCredentials(ctx, deploymentName)
145225
if err != nil {
146-
logger.Err(err).Fatal("failed to create basic data for the connection")
226+
logger.Err(err).Error("failed to create basic data for the connection")
227+
return err
147228
}
148229

149230
if d.GetAcceptedSpec().GetMode() != api.DeploymentModeCluster {
150-
logger.Fatal("agency dump does not work for the \"%s\" deployment \"%s\"", d.GetAcceptedSpec().GetMode(),
231+
err = errors.Errorf("agency state does not work for the \"%s\" deployment \"%s\"", d.GetAcceptedSpec().GetMode(),
151232
d.GetName())
233+
logger.Err(err).Error("Invalid deployment type")
234+
return err
152235
}
153236

154237
endpoint := getArangoEndpoint(d.GetAcceptedSpec().IsSecure(), k8sutil.CreateDatabaseClientServiceDNSName(d.GetObjectMeta()))
@@ -158,26 +241,62 @@ func cmdGetAgencyDump(cmd *cobra.Command, _ []string) {
158241
defer body.Close()
159242
}
160243
if err != nil {
161-
logger.Err(err).Fatal("can not get dump")
244+
logger.Err(err).Error("can not get dump")
245+
return err
162246
}
163247

164-
// Print and receive parallelly.
165-
io.Copy(os.Stdout, body)
248+
// Print and receive parallely.
249+
_, err = io.Copy(os.Stdout, body)
250+
return err
166251
}
167252

168-
// getAgencyState returns the current state in the agency.
169-
func getAgencyState(ctx context.Context, conn connection.Connection) (io.ReadCloser, error) {
170-
url := connection.NewUrl("_api", "agency", "read")
171-
data := []byte(`[["/"]]`)
172-
resp, body, err := connection.CallStream(ctx, conn, goHttp.MethodPost, url, connection.WithBody(data))
253+
// sendStreamRequest sends the request to a member
254+
func sendStreamRequest(ctx context.Context, conn connection.Connection, method string, body []byte, code int, parts ...string) (io.ReadCloser, error) {
255+
url := connection.NewUrl(parts...)
256+
257+
var mods []connection.RequestModifier
258+
259+
if body != nil {
260+
mods = append(mods, connection.WithBody(body))
261+
}
262+
263+
resp, output, err := connection.CallStream(ctx, conn, method, url, mods...)
173264
if err != nil {
174265
return nil, err
175266
}
176-
if resp.Code() != goHttp.StatusOK {
177-
return nil, errors.New(fmt.Sprintf("unexpected HTTP status from \"%s\" endpoint", url))
267+
if resp.Code() != code {
268+
return nil, errors.New(fmt.Sprintf("unexpected HTTP status from \"%s\" endpoint. Expected: '%d', got '%d'", url, code, resp.Code()))
269+
}
270+
271+
return output, nil
272+
}
273+
274+
// sendRequest sends the request to a member and returns object
275+
func sendRequest[OUT any](ctx context.Context, conn connection.Connection, method string, body []byte, code int, parts ...string) (OUT, error) {
276+
url := connection.NewUrl(parts...)
277+
278+
var mods []connection.RequestModifier
279+
280+
if body != nil {
281+
mods = append(mods, connection.WithBody(body))
282+
}
283+
284+
var out OUT
285+
286+
resp, err := connection.Call(ctx, conn, method, url, &out, mods...)
287+
if err != nil {
288+
return util.Default[OUT](), err
289+
}
290+
if resp.Code() != code {
291+
return util.Default[OUT](), errors.New(fmt.Sprintf("unexpected HTTP status from \"%s\" endpoint. Expected: '%d', got '%d'", url, code, resp.Code()))
178292
}
179293

180-
return body, nil
294+
return out, nil
295+
}
296+
297+
// getAgencyState returns the current state in the agency.
298+
func getAgencyState(ctx context.Context, conn connection.Connection) (io.ReadCloser, error) {
299+
return sendStreamRequest(ctx, conn, goHttp.MethodPost, []byte(`[["/"]]`), goHttp.StatusOK, "_api", "agency", "read")
181300
}
182301

183302
// getDeploymentAndCredentials returns deployment and necessary credentials to communicate with ArangoDB pods.
@@ -235,15 +354,10 @@ func getArangoEndpoint(secure bool, dnsName string) string {
235354

236355
// getAgencyLeader returns the leader ID of the agency.
237356
func getAgencyLeader(ctx context.Context, conn connection.Connection) (string, error) {
238-
url := connection.NewUrl("_api", "agency", "config")
239-
output := make(map[string]interface{})
240-
resp, err := connection.CallGet(ctx, conn, url, &output)
357+
output, err := sendRequest[map[string]interface{}](ctx, conn, goHttp.MethodGet, nil, goHttp.StatusOK, "_api", "agency", "config")
241358
if err != nil {
242359
return "", err
243360
}
244-
if resp.Code() != goHttp.StatusOK {
245-
return "", errors.New("unexpected HTTP status from agency-dump endpoint")
246-
}
247361

248362
if leaderID, ok := output["leaderId"]; ok {
249363
if id, ok := leaderID.(string); ok {
@@ -256,16 +370,7 @@ func getAgencyLeader(ctx context.Context, conn connection.Connection) (string, e
256370

257371
// getAgencyDump returns dump of the agency.
258372
func getAgencyDump(ctx context.Context, conn connection.Connection) (io.ReadCloser, error) {
259-
url := connection.NewUrl("_api", "cluster", "agency-dump")
260-
resp, body, err := connection.CallStream(ctx, conn, goHttp.MethodGet, url)
261-
if err != nil {
262-
return nil, err
263-
}
264-
if resp.Code() != goHttp.StatusOK {
265-
return nil, errors.New("unexpected HTTP status from agency-dump endpoint")
266-
}
267-
268-
return body, nil
373+
return sendStreamRequest(ctx, conn, goHttp.MethodGet, nil, goHttp.StatusOK, "_api", "cluster", "agency-dump")
269374
}
270375

271376
type JWTAuthentication struct {

cmd/cmd.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,6 @@ func Execute() int {
293293
return 0
294294
}
295295

296-
// Show usage
297-
func executeUsage(cmd *cobra.Command, args []string) {
298-
cmd.Usage()
299-
}
300-
301296
// Run the operator
302297
func executeMain(cmd *cobra.Command, args []string) {
303298
// Get environment

0 commit comments

Comments
 (0)