Skip to content

Commit ed59c50

Browse files
committed
Revert "Removed Tools support (minio#3467)"
This reverts commit 18e5097.
1 parent e245c56 commit ed59c50

File tree

117 files changed

+15217
-17
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+15217
-17
lines changed

api/admin_health_info.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2021 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package api
18+
19+
import (
20+
"context"
21+
b64 "encoding/base64"
22+
"encoding/json"
23+
"errors"
24+
"fmt"
25+
"net/http"
26+
"net/url"
27+
"os"
28+
"time"
29+
30+
"github.com/minio/console/pkg/logger"
31+
"github.com/minio/console/pkg/utils"
32+
33+
subnet "github.com/minio/console/pkg/subnet"
34+
mc "github.com/minio/mc/cmd"
35+
"github.com/minio/websocket"
36+
)
37+
38+
// startHealthInfo starts fetching mc.ServerHealthInfo and
39+
// sends messages with the corresponding data on the websocket connection
40+
func startHealthInfo(ctx context.Context, conn WSConn, client MinioAdmin, deadline *time.Duration) error {
41+
if deadline == nil {
42+
return errors.New("duration can't be nil on startHealthInfo")
43+
}
44+
45+
// Fetch info of all servers (cluster or single server)
46+
healthInfo, version, err := client.serverHealthInfo(ctx, *deadline)
47+
if err != nil {
48+
return err
49+
}
50+
51+
compressedDiag, err := mc.TarGZHealthInfo(healthInfo, version)
52+
if err != nil {
53+
return err
54+
}
55+
encodedDiag := b64.StdEncoding.EncodeToString(compressedDiag)
56+
type messageReport struct {
57+
Encoded string `json:"encoded"`
58+
ServerHealthInfo interface{} `json:"serverHealthInfo"`
59+
SubnetResponse string `json:"subnetResponse"`
60+
}
61+
62+
ctx = context.WithValue(ctx, utils.ContextClientIP, conn.remoteAddress())
63+
err = sendHealthInfoToSubnet(ctx, compressedDiag, client)
64+
report := messageReport{
65+
Encoded: encodedDiag,
66+
ServerHealthInfo: healthInfo,
67+
SubnetResponse: mc.SubnetBaseURL() + "/health",
68+
}
69+
if err != nil {
70+
report.SubnetResponse = fmt.Sprintf("Error: %s", err.Error())
71+
}
72+
73+
message, err := json.Marshal(report)
74+
if err != nil {
75+
return err
76+
}
77+
78+
// Send Message through websocket connection
79+
return conn.writeMessage(websocket.TextMessage, message)
80+
}
81+
82+
// getHealthInfoOptionsFromReq gets duration for startHealthInfo request
83+
// path come as : `/health-info?deadline=2h`
84+
func getHealthInfoOptionsFromReq(req *http.Request) (*time.Duration, error) {
85+
deadlineDuration, err := time.ParseDuration(req.FormValue("deadline"))
86+
if err != nil {
87+
return nil, err
88+
}
89+
return &deadlineDuration, nil
90+
}
91+
92+
func updateMcGlobals(subnetTokenConfig subnet.LicenseTokenConfig) error {
93+
mc.GlobalDevMode = getConsoleDevMode()
94+
if len(subnetTokenConfig.Proxy) > 0 {
95+
proxyURL, e := url.Parse(subnetTokenConfig.Proxy)
96+
if e != nil {
97+
return e
98+
}
99+
mc.GlobalSubnetProxyURL = proxyURL
100+
}
101+
return nil
102+
}
103+
104+
func sendHealthInfoToSubnet(ctx context.Context, compressedHealthInfo []byte, client MinioAdmin) error {
105+
filename := fmt.Sprintf("health_%d.json.gz", time.Now().Unix())
106+
subnetTokenConfig, e := GetSubnetKeyFromMinIOConfig(ctx, client)
107+
if e != nil {
108+
return e
109+
}
110+
e = updateMcGlobals(*subnetTokenConfig)
111+
if e != nil {
112+
return e
113+
}
114+
var apiKey string
115+
if len(subnetTokenConfig.APIKey) != 0 {
116+
apiKey = subnetTokenConfig.APIKey
117+
} else {
118+
apiKey, e = subnet.GetSubnetAPIKeyUsingLicense(subnetTokenConfig.License)
119+
if e != nil {
120+
return e
121+
}
122+
}
123+
e = os.WriteFile(filename, compressedHealthInfo, 0o666)
124+
if e != nil {
125+
return e
126+
}
127+
headers := mc.SubnetAPIKeyAuthHeaders(apiKey)
128+
resp, e := (&mc.SubnetFileUploader{
129+
FilePath: filename,
130+
ReqURL: mc.SubnetUploadURL("health"),
131+
Headers: headers,
132+
DeleteAfterUpload: true,
133+
}).UploadFileToSubnet()
134+
if e != nil {
135+
// file gets deleted only if upload is successful
136+
// so we delete explicitly here as we already have the bytes
137+
logger.LogIf(ctx, os.Remove(filename))
138+
return e
139+
}
140+
141+
type SubnetResponse struct {
142+
LicenseV2 string `json:"license_v2,omitempty"`
143+
APIKey string `json:"api_key,omitempty"`
144+
}
145+
146+
var subnetResp SubnetResponse
147+
e = json.Unmarshal([]byte(resp), &subnetResp)
148+
if e != nil {
149+
return e
150+
}
151+
152+
return nil
153+
}

api/admin_health_info_test.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2021 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package api
18+
19+
import (
20+
"context"
21+
"encoding/json"
22+
"errors"
23+
"reflect"
24+
"testing"
25+
"time"
26+
27+
madmin "github.com/minio/madmin-go/v3"
28+
)
29+
30+
func Test_serverHealthInfo(t *testing.T) {
31+
var testReceiver chan madmin.HealthInfo
32+
33+
ctx, cancel := context.WithCancel(context.Background())
34+
defer cancel()
35+
client := AdminClientMock{}
36+
mockWSConn := mockConn{}
37+
deadlineDuration, _ := time.ParseDuration("1h")
38+
39+
type args struct {
40+
deadline time.Duration
41+
wsWriteMock func(messageType int, data []byte) error
42+
mockMessages []madmin.HealthInfo
43+
}
44+
tests := []struct {
45+
test string
46+
args args
47+
wantError error
48+
}{
49+
{
50+
test: "Return simple health info, no errors",
51+
args: args{
52+
deadline: deadlineDuration,
53+
mockMessages: []madmin.HealthInfo{{}, {}},
54+
wsWriteMock: func(_ int, data []byte) error {
55+
// mock connection WriteMessage() no error
56+
// emulate that receiver gets the message written
57+
var t madmin.HealthInfo
58+
_ = json.Unmarshal(data, &t)
59+
testReceiver <- t
60+
return nil
61+
},
62+
},
63+
wantError: nil,
64+
},
65+
{
66+
test: "Return simple health info2, no errors",
67+
args: args{
68+
deadline: deadlineDuration,
69+
mockMessages: []madmin.HealthInfo{{}},
70+
wsWriteMock: func(_ int, data []byte) error {
71+
// mock connection WriteMessage() no error
72+
// emulate that receiver gets the message written
73+
var t madmin.HealthInfo
74+
_ = json.Unmarshal(data, &t)
75+
testReceiver <- t
76+
return nil
77+
},
78+
},
79+
wantError: nil,
80+
},
81+
{
82+
test: "Handle error on ws write",
83+
args: args{
84+
deadline: deadlineDuration,
85+
mockMessages: []madmin.HealthInfo{{}},
86+
wsWriteMock: func(_ int, data []byte) error {
87+
// mock connection WriteMessage() no error
88+
// emulate that receiver gets the message written
89+
var t madmin.HealthInfo
90+
_ = json.Unmarshal(data, &t)
91+
return errors.New("error on write")
92+
},
93+
},
94+
wantError: errors.New("error on write"),
95+
},
96+
{
97+
test: "Handle error on health function",
98+
args: args{
99+
deadline: deadlineDuration,
100+
mockMessages: []madmin.HealthInfo{
101+
{
102+
Error: "error on healthInfo",
103+
},
104+
},
105+
wsWriteMock: func(_ int, data []byte) error {
106+
// mock connection WriteMessage() no error
107+
// emulate that receiver gets the message written
108+
var t madmin.HealthInfo
109+
_ = json.Unmarshal(data, &t)
110+
return nil
111+
},
112+
},
113+
wantError: nil,
114+
},
115+
}
116+
for _, tt := range tests {
117+
tt := tt
118+
t.Run(tt.test, func(_ *testing.T) {
119+
// make testReceiver channel
120+
testReceiver = make(chan madmin.HealthInfo, len(tt.args.mockMessages))
121+
// mock function same for all tests, changes mockMessages
122+
minioServerHealthInfoMock = func(_ context.Context,
123+
_ time.Duration,
124+
) (interface{}, string, error) {
125+
info := tt.args.mockMessages[0]
126+
return info, madmin.HealthInfoVersion, nil
127+
}
128+
connWriteMessageMock = tt.args.wsWriteMock
129+
err := startHealthInfo(ctx, mockWSConn, client, &deadlineDuration)
130+
// close test mock channel
131+
close(testReceiver)
132+
// check that the TestReceiver got the same number of data from Console.
133+
index := 0
134+
for info := range testReceiver {
135+
if !reflect.DeepEqual(info, tt.args.mockMessages[index]) {
136+
t.Errorf("startHealthInfo() got: %v, want: %v", info, tt.args.mockMessages[index])
137+
return
138+
}
139+
index++
140+
}
141+
if !reflect.DeepEqual(err, tt.wantError) {
142+
t.Errorf("startHealthInfo() error: %v, wantError: %v", err, tt.wantError)
143+
return
144+
}
145+
})
146+
}
147+
}

0 commit comments

Comments
 (0)