diff --git a/.gitignore b/.gitignore
index a9b8827f9..f7da97cdc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,4 +19,6 @@ vendor/
# Ignore executables
target/
mcs-server
+mcs
+!mcs/
!mcs-server/
diff --git a/Makefile b/Makefile
index 5ccb55b14..e2204885d 100644
--- a/Makefile
+++ b/Makefile
@@ -7,11 +7,17 @@ mcs:
swagger-gen:
@echo "Generating swagger server code from yaml"
- @swagger generate server -A mcs -f ./swagger.yml -r minio_copyright.txt
+ @swagger generate server -A mcs -f ./swagger.yml -r NOTICE
build:
@(cd portal-ui; yarn install; make build; cd ..)
@(CGO_ENABLED=0 go build --tags kqueue --ldflags "-s -w" -o mcs ./cmd/mcs-server)
+test:
+ @(go test ./restapi -v)
+
+coverage:
+ @(go test ./restapi -v -coverprofile=coverage.out && go tool cover -html=coverage.out && open coverage.html)
+
clean:
@rm -vf mcs
diff --git a/models/profiler_type.go b/models/profiler_type.go
new file mode 100644
index 000000000..da388fc57
--- /dev/null
+++ b/models/profiler_type.go
@@ -0,0 +1,95 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package models
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "encoding/json"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/strfmt"
+ "github.com/go-openapi/validate"
+)
+
+// ProfilerType profiler type
+//
+// swagger:model profilerType
+type ProfilerType string
+
+const (
+
+ // ProfilerTypeCPU captures enum value "cpu"
+ ProfilerTypeCPU ProfilerType = "cpu"
+
+ // ProfilerTypeMem captures enum value "mem"
+ ProfilerTypeMem ProfilerType = "mem"
+
+ // ProfilerTypeBlock captures enum value "block"
+ ProfilerTypeBlock ProfilerType = "block"
+
+ // ProfilerTypeMutex captures enum value "mutex"
+ ProfilerTypeMutex ProfilerType = "mutex"
+
+ // ProfilerTypeTrace captures enum value "trace"
+ ProfilerTypeTrace ProfilerType = "trace"
+
+ // ProfilerTypeThreads captures enum value "threads"
+ ProfilerTypeThreads ProfilerType = "threads"
+
+ // ProfilerTypeGoroutines captures enum value "goroutines"
+ ProfilerTypeGoroutines ProfilerType = "goroutines"
+)
+
+// for schema
+var profilerTypeEnum []interface{}
+
+func init() {
+ var res []ProfilerType
+ if err := json.Unmarshal([]byte(`["cpu","mem","block","mutex","trace","threads","goroutines"]`), &res); err != nil {
+ panic(err)
+ }
+ for _, v := range res {
+ profilerTypeEnum = append(profilerTypeEnum, v)
+ }
+}
+
+func (m ProfilerType) validateProfilerTypeEnum(path, location string, value ProfilerType) error {
+ if err := validate.Enum(path, location, value, profilerTypeEnum); err != nil {
+ return err
+ }
+ return nil
+}
+
+// Validate validates this profiler type
+func (m ProfilerType) Validate(formats strfmt.Registry) error {
+ var res []error
+
+ // value enum
+ if err := m.validateProfilerTypeEnum("", "body", m); err != nil {
+ return err
+ }
+
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
diff --git a/models/profiling_start_request.go b/models/profiling_start_request.go
new file mode 100644
index 000000000..c17106710
--- /dev/null
+++ b/models/profiling_start_request.go
@@ -0,0 +1,83 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package models
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/strfmt"
+ "github.com/go-openapi/swag"
+)
+
+// ProfilingStartRequest profiling start request
+//
+// swagger:model profilingStartRequest
+type ProfilingStartRequest struct {
+
+ // type
+ // Required: true
+ Type ProfilerType `json:"type"`
+}
+
+// Validate validates this profiling start request
+func (m *ProfilingStartRequest) Validate(formats strfmt.Registry) error {
+ var res []error
+
+ if err := m.validateType(formats); err != nil {
+ res = append(res, err)
+ }
+
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
+
+func (m *ProfilingStartRequest) validateType(formats strfmt.Registry) error {
+
+ if err := m.Type.Validate(formats); err != nil {
+ if ve, ok := err.(*errors.Validation); ok {
+ return ve.ValidateName("type")
+ }
+ return err
+ }
+
+ return nil
+}
+
+// MarshalBinary interface implementation
+func (m *ProfilingStartRequest) MarshalBinary() ([]byte, error) {
+ if m == nil {
+ return nil, nil
+ }
+ return swag.WriteJSON(m)
+}
+
+// UnmarshalBinary interface implementation
+func (m *ProfilingStartRequest) UnmarshalBinary(b []byte) error {
+ var res ProfilingStartRequest
+ if err := swag.ReadJSON(b, &res); err != nil {
+ return err
+ }
+ *m = res
+ return nil
+}
diff --git a/models/start_profiling_item.go b/models/start_profiling_item.go
new file mode 100644
index 000000000..5ecb3a565
--- /dev/null
+++ b/models/start_profiling_item.go
@@ -0,0 +1,66 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package models
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "github.com/go-openapi/strfmt"
+ "github.com/go-openapi/swag"
+)
+
+// StartProfilingItem start profiling item
+//
+// swagger:model startProfilingItem
+type StartProfilingItem struct {
+
+ // error
+ Error string `json:"error,omitempty"`
+
+ // node name
+ NodeName string `json:"nodeName,omitempty"`
+
+ // success
+ Success bool `json:"success,omitempty"`
+}
+
+// Validate validates this start profiling item
+func (m *StartProfilingItem) Validate(formats strfmt.Registry) error {
+ return nil
+}
+
+// MarshalBinary interface implementation
+func (m *StartProfilingItem) MarshalBinary() ([]byte, error) {
+ if m == nil {
+ return nil, nil
+ }
+ return swag.WriteJSON(m)
+}
+
+// UnmarshalBinary interface implementation
+func (m *StartProfilingItem) UnmarshalBinary(b []byte) error {
+ var res StartProfilingItem
+ if err := swag.ReadJSON(b, &res); err != nil {
+ return err
+ }
+ *m = res
+ return nil
+}
diff --git a/models/start_profiling_list.go b/models/start_profiling_list.go
new file mode 100644
index 000000000..0e2202e29
--- /dev/null
+++ b/models/start_profiling_list.go
@@ -0,0 +1,100 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package models
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "strconv"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/strfmt"
+ "github.com/go-openapi/swag"
+)
+
+// StartProfilingList start profiling list
+//
+// swagger:model startProfilingList
+type StartProfilingList struct {
+
+ // start results
+ StartResults []*StartProfilingItem `json:"startResults"`
+
+ // number of start results
+ Total int64 `json:"total,omitempty"`
+}
+
+// Validate validates this start profiling list
+func (m *StartProfilingList) Validate(formats strfmt.Registry) error {
+ var res []error
+
+ if err := m.validateStartResults(formats); err != nil {
+ res = append(res, err)
+ }
+
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
+
+func (m *StartProfilingList) validateStartResults(formats strfmt.Registry) error {
+
+ if swag.IsZero(m.StartResults) { // not required
+ return nil
+ }
+
+ for i := 0; i < len(m.StartResults); i++ {
+ if swag.IsZero(m.StartResults[i]) { // not required
+ continue
+ }
+
+ if m.StartResults[i] != nil {
+ if err := m.StartResults[i].Validate(formats); err != nil {
+ if ve, ok := err.(*errors.Validation); ok {
+ return ve.ValidateName("startResults" + "." + strconv.Itoa(i))
+ }
+ return err
+ }
+ }
+
+ }
+
+ return nil
+}
+
+// MarshalBinary interface implementation
+func (m *StartProfilingList) MarshalBinary() ([]byte, error) {
+ if m == nil {
+ return nil, nil
+ }
+ return swag.WriteJSON(m)
+}
+
+// UnmarshalBinary interface implementation
+func (m *StartProfilingList) UnmarshalBinary(b []byte) error {
+ var res StartProfilingList
+ if err := swag.ReadJSON(b, &res); err != nil {
+ return err
+ }
+ *m = res
+ return nil
+}
diff --git a/restapi/admin_policies.go b/restapi/admin_policies.go
index dd405c65a..fd82a69b1 100644
--- a/restapi/admin_policies.go
+++ b/restapi/admin_policies.go
@@ -111,8 +111,7 @@ func parseRawPolicy(rawPolicy *rawPolicy) *models.Policy {
// listPolicies() converts the map[string][]byte returned by client.listPolicies()
// to []*models.Policy by iterating over each key in policyRawMap and
// then using Unmarshal on the raw bytes to create a *models.Policy
-func listPolicies(client MinioAdmin) ([]*models.Policy, error) {
- ctx := context.Background()
+func listPolicies(ctx context.Context, client MinioAdmin) ([]*models.Policy, error) {
policyRawMap, err := client.listPolicies(ctx)
var policies []*models.Policy
if err != nil {
@@ -132,6 +131,7 @@ func listPolicies(client MinioAdmin) ([]*models.Policy, error) {
// getListPoliciesResponse performs listPolicies() and serializes it to the handler's output
func getListPoliciesResponse() (*models.ListPoliciesResponse, error) {
+ ctx := context.Background()
mAdmin, err := newMAdminClient()
if err != nil {
log.Println("error creating Madmin Client:", err)
@@ -141,7 +141,7 @@ func getListPoliciesResponse() (*models.ListPoliciesResponse, error) {
// defining the client to be used
adminClient := adminClient{client: mAdmin}
- policies, err := listPolicies(adminClient)
+ policies, err := listPolicies(ctx, adminClient)
if err != nil {
log.Println("error listing policies:", err)
return nil, err
@@ -155,8 +155,7 @@ func getListPoliciesResponse() (*models.ListPoliciesResponse, error) {
}
// removePolicy() calls MinIO server to remove a policy based on name.
-func removePolicy(client MinioAdmin, name string) error {
- ctx := context.Background()
+func removePolicy(ctx context.Context, client MinioAdmin, name string) error {
err := client.removePolicy(ctx, name)
if err != nil {
return err
@@ -166,6 +165,7 @@ func removePolicy(client MinioAdmin, name string) error {
// getRemovePolicyResponse() performs removePolicy() and serializes it to the handler's output
func getRemovePolicyResponse(params admin_api.RemovePolicyParams) error {
+ ctx := context.Background()
if params.Name == "" {
log.Println("error policy name not in request")
return errors.New(500, "error policy name not in request")
@@ -179,7 +179,7 @@ func getRemovePolicyResponse(params admin_api.RemovePolicyParams) error {
// defining the client to be used
adminClient := adminClient{client: mAdmin}
- if err := removePolicy(adminClient, params.Name); err != nil {
+ if err := removePolicy(ctx, adminClient, params.Name); err != nil {
log.Println("error removing policy:", err)
return err
}
@@ -190,12 +190,11 @@ func getRemovePolicyResponse(params admin_api.RemovePolicyParams) error {
// addPolicy() takes name and policy in string format, policy
// policy must be string in json format, in the future this will change
// to a Policy struct{} - https://github.com/minio/minio/issues/9171
-func addPolicy(client MinioAdmin, name, policy string) (*models.Policy, error) {
- ctx := context.Background()
+func addPolicy(ctx context.Context, client MinioAdmin, name, policy string) (*models.Policy, error) {
if err := client.addPolicy(ctx, name, policy); err != nil {
return nil, err
}
- policyObject, err := policyInfo(client, name)
+ policyObject, err := policyInfo(ctx, client, name)
if err != nil {
return nil, err
}
@@ -204,6 +203,7 @@ func addPolicy(client MinioAdmin, name, policy string) (*models.Policy, error) {
// getAddPolicyResponse performs addPolicy() and serializes it to the handler's output
func getAddPolicyResponse(params *models.AddPolicyRequest) (*models.Policy, error) {
+ ctx := context.Background()
if params == nil {
log.Println("error AddPolicy body not in request")
return nil, errors.New(500, "error AddPolicy body not in request")
@@ -217,7 +217,7 @@ func getAddPolicyResponse(params *models.AddPolicyRequest) (*models.Policy, erro
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := adminClient{client: mAdmin}
- policy, err := addPolicy(adminClient, *params.Name, params.Definition)
+ policy, err := addPolicy(ctx, adminClient, *params.Name, params.Definition)
if err != nil {
log.Println("error adding policy")
return nil, err
@@ -229,8 +229,7 @@ func getAddPolicyResponse(params *models.AddPolicyRequest) (*models.Policy, erro
// policyInfo() takes a policy name, obtains an []byte (represents a string in JSON format)
// from the MinIO server and then convert it to *models.Policy , in the future this will change
// to a Policy struct{} - https://github.com/minio/minio/issues/9171
-func policyInfo(client MinioAdmin, name string) (*models.Policy, error) {
- ctx := context.Background()
+func policyInfo(ctx context.Context, client MinioAdmin, name string) (*models.Policy, error) {
policyRaw, err := client.getPolicy(ctx, name)
if err != nil {
return nil, err
@@ -246,6 +245,7 @@ func policyInfo(client MinioAdmin, name string) (*models.Policy, error) {
// getPolicyInfoResponse performs policyInfo() and serializes it to the handler's output
func getPolicyInfoResponse(params admin_api.PolicyInfoParams) (*models.Policy, error) {
+ ctx := context.Background()
mAdmin, err := newMAdminClient()
if err != nil {
log.Println("error creating Madmin Client:", err)
@@ -254,7 +254,7 @@ func getPolicyInfoResponse(params admin_api.PolicyInfoParams) (*models.Policy, e
// create a MinIO Admin Client interface implementation
// defining the client to be used
adminClient := adminClient{client: mAdmin}
- policy, err := policyInfo(adminClient, params.Name)
+ policy, err := policyInfo(ctx, adminClient, params.Name)
if err != nil {
log.Println("error getting group info:", err)
return nil, err
@@ -263,12 +263,11 @@ func getPolicyInfoResponse(params admin_api.PolicyInfoParams) (*models.Policy, e
}
// setPolicy() calls MinIO server to assign policy to a group or user.
-func setPolicy(client MinioAdmin, name, entityName string, entityType models.PolicyEntity) error {
+func setPolicy(ctx context.Context, client MinioAdmin, name, entityName string, entityType models.PolicyEntity) error {
isGroup := false
if entityType == "group" {
isGroup = true
}
- ctx := context.Background()
if err := client.setPolicy(ctx, name, entityName, isGroup); err != nil {
return err
}
@@ -277,6 +276,7 @@ func setPolicy(client MinioAdmin, name, entityName string, entityType models.Pol
// getSetPolicyResponse() performs setPolicy() and serializes it to the handler's output
func getSetPolicyResponse(name string, params *models.SetPolicyRequest) error {
+ ctx := context.Background()
if name == "" {
log.Println("error policy name not in request")
return errors.New(500, "error policy name not in request")
@@ -290,7 +290,7 @@ func getSetPolicyResponse(name string, params *models.SetPolicyRequest) error {
// defining the client to be used
adminClient := adminClient{client: mAdmin}
- if err := setPolicy(adminClient, name, *params.EntityName, params.EntityType); err != nil {
+ if err := setPolicy(ctx, adminClient, name, *params.EntityName, params.EntityType); err != nil {
log.Println("error setting policy:", err)
return err
}
diff --git a/restapi/admin_policies_test.go b/restapi/admin_policies_test.go
index 7b43340fd..3cbe4dda0 100644
--- a/restapi/admin_policies_test.go
+++ b/restapi/admin_policies_test.go
@@ -60,6 +60,7 @@ func (ac adminClientMock) setPolicy(ctx context.Context, policyName, entityName
}
func TestListPolicies(t *testing.T) {
+ ctx := context.Background()
assert := assert.New(t)
adminClient := adminClientMock{}
mockPoliciesList := map[string][]byte{
@@ -116,7 +117,7 @@ func TestListPolicies(t *testing.T) {
}
// Test-1 : listPolicies() Get response from minio client with three Canned Policies and return the same number on listPolicies()
function := "listPolicies()"
- policiesList, err := listPolicies(adminClient)
+ policiesList, err := listPolicies(ctx, adminClient)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
@@ -147,7 +148,7 @@ func TestListPolicies(t *testing.T) {
minioListPoliciesMock = func() (map[string][]byte, error) {
return nil, errors.New("error")
}
- _, err = listPolicies(adminClient)
+ _, err = listPolicies(ctx, adminClient)
if assert.Error(err) {
assert.Equal("error", err.Error())
}
@@ -158,13 +159,15 @@ func TestListPolicies(t *testing.T) {
}
return malformedData, nil
}
- _, err = listPolicies(adminClient)
+ _, err = listPolicies(ctx, adminClient)
if assert.Error(err) {
assert.NotEmpty(err.Error())
}
}
func TestRemovePolicy(t *testing.T) {
+ ctx := context.Background()
+
assert := assert.New(t)
adminClient := adminClientMock{}
// Test-1 : removePolicy() remove an existing policy
@@ -173,19 +176,20 @@ func TestRemovePolicy(t *testing.T) {
return nil
}
function := "removePolicy()"
- if err := removePolicy(adminClient, policyToRemove); err != nil {
+ if err := removePolicy(ctx, adminClient, policyToRemove); err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
// Test-2 : removePolicy() Return error and see that the error is handled correctly and returned
minioRemovePolicyMock = func(name string) error {
return errors.New("error")
}
- if err := removePolicy(adminClient, policyToRemove); assert.Error(err) {
+ if err := removePolicy(ctx, adminClient, policyToRemove); assert.Error(err) {
assert.Equal("error", err.Error())
}
}
func TestAddPolicy(t *testing.T) {
+ ctx := context.Background()
assert := assert.New(t)
adminClient := adminClientMock{}
policyName := "new-policy"
@@ -209,7 +213,7 @@ func TestAddPolicy(t *testing.T) {
}
// Test-1 : addPolicy() adds a new policy
function := "addPolicy()"
- policy, err := addPolicy(adminClient, policyName, policyDefinition)
+ policy, err := addPolicy(ctx, adminClient, policyName, policyDefinition)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
@@ -220,7 +224,7 @@ func TestAddPolicy(t *testing.T) {
minioAddPolicyMock = func(name, policy string) error {
return errors.New("error")
}
- if _, err := addPolicy(adminClient, policyName, policyDefinition); assert.Error(err) {
+ if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); assert.Error(err) {
assert.Equal("error", err.Error())
}
// Test-3 : addPolicy() got an error while retrieving policy
@@ -230,19 +234,20 @@ func TestAddPolicy(t *testing.T) {
minioGetPolicyMock = func(name string) (bytes []byte, err error) {
return nil, errors.New("error")
}
- if _, err := addPolicy(adminClient, policyName, policyDefinition); assert.Error(err) {
+ if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); assert.Error(err) {
assert.Equal("error", err.Error())
}
// Test-4 : addPolicy() got an error while parsing policy
minioGetPolicyMock = func(name string) (bytes []byte, err error) {
return []byte("eaeaeaeae"), nil
}
- if _, err := addPolicy(adminClient, policyName, policyDefinition); assert.Error(err) {
+ if _, err := addPolicy(ctx, adminClient, policyName, policyDefinition); assert.Error(err) {
assert.NotEmpty(err.Error())
}
}
func TestSetPolicy(t *testing.T) {
+ ctx := context.Background()
assert := assert.New(t)
adminClient := adminClientMock{}
policyName := "readOnly"
@@ -253,13 +258,13 @@ func TestSetPolicy(t *testing.T) {
}
// Test-1 : setPolicy() set policy to user
function := "setPolicy()"
- err := setPolicy(adminClient, policyName, entityName, entityObject)
+ err := setPolicy(ctx, adminClient, policyName, entityName, entityObject)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
// Test-2 : setPolicy() set policy to group
entityObject = models.PolicyEntityGroup
- err = setPolicy(adminClient, policyName, entityName, entityObject)
+ err = setPolicy(ctx, adminClient, policyName, entityName, entityObject)
if err != nil {
t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
}
@@ -268,7 +273,7 @@ func TestSetPolicy(t *testing.T) {
minioSetPolicyMock = func(policyName, entityName string, isGroup bool) error {
return errors.New("error")
}
- if err := setPolicy(adminClient, policyName, entityName, entityObject); assert.Error(err) {
+ if err := setPolicy(ctx, adminClient, policyName, entityName, entityObject); assert.Error(err) {
assert.Equal("error", err.Error())
}
// Test-4 : setPolicy() set policy to group and get error
@@ -276,7 +281,7 @@ func TestSetPolicy(t *testing.T) {
minioSetPolicyMock = func(policyName, entityName string, isGroup bool) error {
return errors.New("error")
}
- if err := setPolicy(adminClient, policyName, entityName, entityObject); assert.Error(err) {
+ if err := setPolicy(ctx, adminClient, policyName, entityName, entityObject); assert.Error(err) {
assert.Equal("error", err.Error())
}
}
diff --git a/restapi/admin_profiliing_test.go b/restapi/admin_profiliing_test.go
new file mode 100644
index 000000000..264121068
--- /dev/null
+++ b/restapi/admin_profiliing_test.go
@@ -0,0 +1,118 @@
+// This file is part of MinIO Kubernetes Cloud
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package restapi
+
+import (
+ "bytes"
+ "context"
+ "io"
+ "testing"
+
+ "errors"
+
+ "github.com/minio/m3/mcs/models"
+ "github.com/minio/minio/pkg/madmin"
+ "github.com/stretchr/testify/assert"
+)
+
+var minioStartProfiling func(profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error)
+var minioStopProfiling func() (io.ReadCloser, error)
+
+// mock function of startProfiling()
+func (ac adminClientMock) startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
+ return minioStartProfiling(profiler)
+}
+
+// mock function of stopProfiling()
+func (ac adminClientMock) stopProfiling(ctx context.Context) (io.ReadCloser, error) {
+ return minioStopProfiling()
+}
+
+func TestStartProfiling(t *testing.T) {
+ ctx := context.Background()
+ assert := assert.New(t)
+ adminClient := adminClientMock{}
+ // Test-1 : startProfiling() Get response from Minio server with one profiling object
+ // mock function response from startProfiling()
+ minioStartProfiling = func(profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
+ return []madmin.StartProfilingResult{
+ {
+ NodeName: "http://127.0.0.1:9000/",
+ Success: true,
+ Error: "",
+ },
+ {
+ NodeName: "http://127.0.0.1:9001/",
+ Success: true,
+ Error: "",
+ },
+ }, nil
+ }
+ function := "startProfiling()"
+ cpuProfiler := models.ProfilerType("cpu")
+ startProfilingResults, err := startProfiling(ctx, adminClient, cpuProfiler)
+ if err != nil {
+ t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
+ }
+ assert.Equal(2, len(startProfilingResults))
+ //Test-2 : startProfiling() Correctly handles errors returned by Minio
+ //mock function response from startProfiling()
+ minioStartProfiling = func(profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
+ return nil, errors.New("error")
+ }
+ _, err = startProfiling(ctx, adminClient, cpuProfiler)
+ if assert.Error(err) {
+ assert.Equal("error", err.Error())
+ }
+}
+
+// Implementing fake closingBuffer need it to mock stopProfiling() (io.ReadCloser, error)
+type ClosingBuffer struct {
+ *bytes.Buffer
+}
+
+// Implementing a fake Close function for io.ReadCloser
+func (cb *ClosingBuffer) Close() error {
+ return nil
+}
+
+func TestStopProfiling(t *testing.T) {
+ ctx := context.Background()
+ assert := assert.New(t)
+ adminClient := adminClientMock{}
+ // Test-1 : stopProfiling() Get response from Minio server and that response is a readCloser interface
+ // mock function response from startProfiling()
+ minioStopProfiling = func() (io.ReadCloser, error) {
+ return &ClosingBuffer{bytes.NewBufferString("In memory string eaeae")}, nil
+ }
+ function := "stopProfiling()"
+ readCloserInterface, err := stopProfiling(ctx, adminClient)
+ if err != nil {
+ t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
+ }
+ // Check return type of stopProfiling is io.ReadCloser by doing a cast
+ assert.NotPanics(func() { readCloserInterface.(io.ReadCloser).Close() })
+ // Test-2 : stopProfiling() Correctly handles errors returned by Minio
+ // mock function response from stopProfiling()
+ minioStopProfiling = func() (io.ReadCloser, error) {
+ return nil, errors.New("error")
+ }
+ _, err = stopProfiling(ctx, adminClient)
+ if assert.Error(err) {
+ assert.Equal("error", err.Error())
+ }
+}
diff --git a/restapi/admin_profiling.go b/restapi/admin_profiling.go
new file mode 100644
index 000000000..643b66bb9
--- /dev/null
+++ b/restapi/admin_profiling.go
@@ -0,0 +1,146 @@
+// This file is part of MinIO Kubernetes Cloud
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package restapi
+
+import (
+ "context"
+ "io"
+ "log"
+ "net/http"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/runtime"
+ "github.com/go-openapi/runtime/middleware"
+ "github.com/go-openapi/swag"
+ "github.com/minio/m3/mcs/models"
+ "github.com/minio/m3/mcs/restapi/operations"
+ "github.com/minio/m3/mcs/restapi/operations/admin_api"
+ "github.com/minio/minio/pkg/madmin"
+)
+
+func registerProfilingHandler(api *operations.McsAPI) {
+ // Start Profiling
+ api.AdminAPIProfilingStartHandler = admin_api.ProfilingStartHandlerFunc(func(params admin_api.ProfilingStartParams, principal interface{}) middleware.Responder {
+ profilingStartResponse, err := getProfilingStartResponse(params.Body)
+ if err != nil {
+ return admin_api.NewProfilingStartDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
+ }
+ return admin_api.NewProfilingStartCreated().WithPayload(profilingStartResponse)
+ })
+ // Stop and download profiling data
+ api.AdminAPIProfilingStopHandler = admin_api.ProfilingStopHandlerFunc(func(params admin_api.ProfilingStopParams, principal interface{}) middleware.Responder {
+ profilingStopResponse, err := getProfilingStopResponse()
+ if err != nil {
+ return admin_api.NewProfilingStopDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
+ }
+ // Custom response writer to set the content-disposition header to tell the
+ // HTTP client the name and extension of the file we are returning
+ return middleware.ResponderFunc(func(w http.ResponseWriter, _ runtime.Producer) {
+ w.Header().Set("Content-Type", "application/octet-stream")
+ w.Header().Set("Content-Disposition", "attachment; filename=profile.zip")
+ if _, err := io.Copy(w, profilingStopResponse); err != nil {
+ log.Println(err)
+ } else {
+ if err := profilingStopResponse.Close(); err != nil {
+ log.Println(err)
+ }
+ }
+ })
+ })
+}
+
+// startProfiling() starts the profiling on the Minio server
+// Enable 1 of the 7 profiling mechanisms: "cpu","mem","block","mutex","trace","threads","goroutines"
+// in the Minio server, returns []*models.StartProfilingItem that contains individual status of this operation
+// for each Minio node, ie:
+//
+// {
+// "Success": true,
+// "nodeName": "127.0.0.1:9000"
+// "error": ""
+// }
+func startProfiling(ctx context.Context, client MinioAdmin, profilerType models.ProfilerType) ([]*models.StartProfilingItem, error) {
+ profilingResults, err := client.startProfiling(ctx, madmin.ProfilerType(profilerType))
+ if err != nil {
+ return nil, err
+ }
+ var items []*models.StartProfilingItem
+ for _, result := range profilingResults {
+ items = append(items, &models.StartProfilingItem{
+ Success: result.Success,
+ Error: result.Error,
+ NodeName: result.NodeName,
+ })
+ }
+ return items, nil
+}
+
+// getProfilingStartResponse performs startProfiling() and serializes it to the handler's output
+func getProfilingStartResponse(params *models.ProfilingStartRequest) (*models.StartProfilingList, error) {
+ ctx := context.Background()
+ if params == nil {
+ log.Println("error profiling type not in body request")
+ return nil, errors.New(500, "error AddPolicy body not in request")
+ }
+ mAdmin, err := newMAdminClient()
+ if err != nil {
+ log.Println("error creating Madmin Client:", err)
+ return nil, err
+ }
+ // create a MinIO Admin Client interface implementation
+ // defining the client to be used
+ adminClient := adminClient{client: mAdmin}
+ profilingItems, err := startProfiling(ctx, adminClient, params.Type)
+ if err != nil {
+ log.Println("error starting profiling:", err)
+ return nil, err
+ }
+ profilingList := &models.StartProfilingList{
+ StartResults: profilingItems,
+ Total: int64(len(profilingItems)),
+ }
+ return profilingList, nil
+}
+
+// stopProfiling() stop the profiling on the Minio server and returns
+// the generated Zip file as io.ReadCloser
+func stopProfiling(ctx context.Context, client MinioAdmin) (io.ReadCloser, error) {
+ profilingData, err := client.stopProfiling(ctx)
+ if err != nil {
+ return nil, err
+ }
+ return profilingData, nil
+}
+
+// getProfilingStopResponse() performs setPolicy() and serializes it to the handler's output
+func getProfilingStopResponse() (io.ReadCloser, error) {
+ ctx := context.Background()
+ mAdmin, err := newMAdminClient()
+ if err != nil {
+ log.Println("error creating Madmin Client:", err)
+ return nil, err
+ }
+ // create a MinIO Admin Client interface implementation
+ // defining the client to be used
+ adminClient := adminClient{client: mAdmin}
+ profilingData, err := stopProfiling(ctx, adminClient)
+ if err != nil {
+ log.Println("error stopping profiling:", err)
+ return nil, err
+ }
+ return profilingData, nil
+}
diff --git a/restapi/client-admin.go b/restapi/client-admin.go
index 0a935f57b..4c6daf2fa 100644
--- a/restapi/client-admin.go
+++ b/restapi/client-admin.go
@@ -20,6 +20,7 @@ import (
"context"
"crypto/tls"
"hash/fnv"
+ "io"
"net"
"net/http"
"net/url"
@@ -141,7 +142,7 @@ type MinioAdmin interface {
addUser(ctx context.Context, acessKey, SecretKey string) error
listGroups(ctx context.Context) ([]string, error)
updateGroupMembers(ctx context.Context, greq madmin.GroupAddRemove) error
- getGroupDescription(ctx context.Context, grouo string) (*madmin.GroupDesc, error)
+ getGroupDescription(ctx context.Context, group string) (*madmin.GroupDesc, error)
setGroupStatus(ctx context.Context, group string, status madmin.GroupStatus) error
listPolicies(ctx context.Context) (map[string][]byte, error)
getPolicy(ctx context.Context, name string) ([]byte, error)
@@ -153,6 +154,8 @@ type MinioAdmin interface {
setConfigKV(ctx context.Context, kv string) (err error)
serviceRestart(ctx context.Context) error
serverInfo(ctx context.Context) (madmin.InfoMessage, error)
+ startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error)
+ stopProfiling(ctx context.Context) (io.ReadCloser, error)
}
// Interface implementation
@@ -243,6 +246,16 @@ func (ac adminClient) serverInfo(ctx context.Context) (madmin.InfoMessage, error
return ac.client.ServerInfo(ctx)
}
+// implements madmin.StartProfiling()
+func (ac adminClient) startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
+ return ac.client.StartProfiling(ctx, profiler)
+}
+
+// implements madmin.DownloadProfilingData()
+func (ac adminClient) stopProfiling(ctx context.Context) (io.ReadCloser, error) {
+ return ac.client.DownloadProfilingData(ctx)
+}
+
func newMAdminClient() (*madmin.AdminClient, error) {
endpoint := getMinIOServer()
accessKeyID := getAccessKey()
diff --git a/restapi/configure_mcs.go b/restapi/configure_mcs.go
index a8871fc27..31957d486 100644
--- a/restapi/configure_mcs.go
+++ b/restapi/configure_mcs.go
@@ -83,6 +83,8 @@ func configureAPI(api *operations.McsAPI) http.Handler {
registerBucketEventsHandlers(api)
// Register service handlers
registerServiceHandlers(api)
+ // Register profiling handlers
+ registerProfilingHandler(api)
api.PreServerShutdown = func() {}
diff --git a/restapi/doc.go b/restapi/doc.go
index bd18dcc26..957007825 100644
--- a/restapi/doc.go
+++ b/restapi/doc.go
@@ -28,6 +28,7 @@
// - application/json
//
// Produces:
+// - application/octet-stream
// - application/json
//
// swagger:meta
diff --git a/restapi/embedded_spec.go b/restapi/embedded_spec.go
index 49ac859a4..cc8451737 100644
--- a/restapi/embedded_spec.go
+++ b/restapi/embedded_spec.go
@@ -701,6 +701,65 @@ func init() {
}
}
},
+ "/api/v1/profiling/start": {
+ "post": {
+ "tags": [
+ "AdminAPI"
+ ],
+ "summary": "Start recording profile data",
+ "operationId": "ProfilingStart",
+ "parameters": [
+ {
+ "name": "body",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/profilingStartRequest"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/startProfilingList"
+ }
+ },
+ "default": {
+ "description": "Generic error response.",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/profiling/stop": {
+ "post": {
+ "produces": [
+ "application/octet-stream"
+ ],
+ "tags": [
+ "AdminAPI"
+ ],
+ "summary": "Stop and download profile data",
+ "operationId": "ProfilingStop",
+ "responses": {
+ "201": {
+ "description": "A successful response.",
+ "schema": {
+ "type": "file"
+ }
+ },
+ "default": {
+ "description": "Generic error response.",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ }
+ },
"/api/v1/service/restart": {
"post": {
"tags": [
@@ -1185,6 +1244,29 @@ func init() {
"principal": {
"type": "string"
},
+ "profilerType": {
+ "type": "string",
+ "enum": [
+ "cpu",
+ "mem",
+ "block",
+ "mutex",
+ "trace",
+ "threads",
+ "goroutines"
+ ]
+ },
+ "profilingStartRequest": {
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "$ref": "#/definitions/profilerType"
+ }
+ }
+ },
"setBucketPolicyRequest": {
"type": "object",
"required": [
@@ -1230,6 +1312,36 @@ func init() {
}
}
},
+ "startProfilingItem": {
+ "type": "object",
+ "properties": {
+ "error": {
+ "type": "string"
+ },
+ "nodeName": {
+ "type": "string"
+ },
+ "success": {
+ "type": "boolean"
+ }
+ }
+ },
+ "startProfilingList": {
+ "type": "object",
+ "properties": {
+ "startResults": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/startProfilingItem"
+ }
+ },
+ "total": {
+ "type": "integer",
+ "format": "int64",
+ "title": "number of start results"
+ }
+ }
+ },
"statement": {
"type": "object",
"properties": {
@@ -1970,6 +2082,65 @@ func init() {
}
}
},
+ "/api/v1/profiling/start": {
+ "post": {
+ "tags": [
+ "AdminAPI"
+ ],
+ "summary": "Start recording profile data",
+ "operationId": "ProfilingStart",
+ "parameters": [
+ {
+ "name": "body",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/profilingStartRequest"
+ }
+ }
+ ],
+ "responses": {
+ "201": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/startProfilingList"
+ }
+ },
+ "default": {
+ "description": "Generic error response.",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ }
+ },
+ "/api/v1/profiling/stop": {
+ "post": {
+ "produces": [
+ "application/octet-stream"
+ ],
+ "tags": [
+ "AdminAPI"
+ ],
+ "summary": "Stop and download profile data",
+ "operationId": "ProfilingStop",
+ "responses": {
+ "201": {
+ "description": "A successful response.",
+ "schema": {
+ "type": "file"
+ }
+ },
+ "default": {
+ "description": "Generic error response.",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ }
+ },
"/api/v1/service/restart": {
"post": {
"tags": [
@@ -2454,6 +2625,29 @@ func init() {
"principal": {
"type": "string"
},
+ "profilerType": {
+ "type": "string",
+ "enum": [
+ "cpu",
+ "mem",
+ "block",
+ "mutex",
+ "trace",
+ "threads",
+ "goroutines"
+ ]
+ },
+ "profilingStartRequest": {
+ "type": "object",
+ "required": [
+ "type"
+ ],
+ "properties": {
+ "type": {
+ "$ref": "#/definitions/profilerType"
+ }
+ }
+ },
"setBucketPolicyRequest": {
"type": "object",
"required": [
@@ -2499,6 +2693,36 @@ func init() {
}
}
},
+ "startProfilingItem": {
+ "type": "object",
+ "properties": {
+ "error": {
+ "type": "string"
+ },
+ "nodeName": {
+ "type": "string"
+ },
+ "success": {
+ "type": "boolean"
+ }
+ }
+ },
+ "startProfilingList": {
+ "type": "object",
+ "properties": {
+ "startResults": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/startProfilingItem"
+ }
+ },
+ "total": {
+ "type": "integer",
+ "format": "int64",
+ "title": "number of start results"
+ }
+ }
+ },
"statement": {
"type": "object",
"properties": {
diff --git a/restapi/operations/admin_api/profiling_start.go b/restapi/operations/admin_api/profiling_start.go
new file mode 100644
index 000000000..14fa5d27c
--- /dev/null
+++ b/restapi/operations/admin_api/profiling_start.go
@@ -0,0 +1,88 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/runtime/middleware"
+)
+
+// ProfilingStartHandlerFunc turns a function with the right signature into a profiling start handler
+type ProfilingStartHandlerFunc func(ProfilingStartParams, interface{}) middleware.Responder
+
+// Handle executing the request and returning a response
+func (fn ProfilingStartHandlerFunc) Handle(params ProfilingStartParams, principal interface{}) middleware.Responder {
+ return fn(params, principal)
+}
+
+// ProfilingStartHandler interface for that can handle valid profiling start params
+type ProfilingStartHandler interface {
+ Handle(ProfilingStartParams, interface{}) middleware.Responder
+}
+
+// NewProfilingStart creates a new http.Handler for the profiling start operation
+func NewProfilingStart(ctx *middleware.Context, handler ProfilingStartHandler) *ProfilingStart {
+ return &ProfilingStart{Context: ctx, Handler: handler}
+}
+
+/*ProfilingStart swagger:route POST /api/v1/profiling/start AdminAPI profilingStart
+
+Start recording profile data
+
+*/
+type ProfilingStart struct {
+ Context *middleware.Context
+ Handler ProfilingStartHandler
+}
+
+func (o *ProfilingStart) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+ route, rCtx, _ := o.Context.RouteInfo(r)
+ if rCtx != nil {
+ r = rCtx
+ }
+ var Params = NewProfilingStartParams()
+
+ uprinc, aCtx, err := o.Context.Authorize(r, route)
+ if err != nil {
+ o.Context.Respond(rw, r, route.Produces, route, err)
+ return
+ }
+ if aCtx != nil {
+ r = aCtx
+ }
+ var principal interface{}
+ if uprinc != nil {
+ principal = uprinc
+ }
+
+ if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
+ o.Context.Respond(rw, r, route.Produces, route, err)
+ return
+ }
+
+ res := o.Handler.Handle(Params, principal) // actually handle the request
+
+ o.Context.Respond(rw, r, route.Produces, route, res)
+
+}
diff --git a/restapi/operations/admin_api/profiling_start_parameters.go b/restapi/operations/admin_api/profiling_start_parameters.go
new file mode 100644
index 000000000..99f021529
--- /dev/null
+++ b/restapi/operations/admin_api/profiling_start_parameters.go
@@ -0,0 +1,94 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "io"
+ "net/http"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/runtime"
+ "github.com/go-openapi/runtime/middleware"
+
+ "github.com/minio/m3/mcs/models"
+)
+
+// NewProfilingStartParams creates a new ProfilingStartParams object
+// no default values defined in spec.
+func NewProfilingStartParams() ProfilingStartParams {
+
+ return ProfilingStartParams{}
+}
+
+// ProfilingStartParams contains all the bound params for the profiling start operation
+// typically these are obtained from a http.Request
+//
+// swagger:parameters ProfilingStart
+type ProfilingStartParams struct {
+
+ // HTTP Request Object
+ HTTPRequest *http.Request `json:"-"`
+
+ /*
+ Required: true
+ In: body
+ */
+ Body *models.ProfilingStartRequest
+}
+
+// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
+// for simple values it will use straight method calls.
+//
+// To ensure default values, the struct must have been initialized with NewProfilingStartParams() beforehand.
+func (o *ProfilingStartParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
+ var res []error
+
+ o.HTTPRequest = r
+
+ if runtime.HasBody(r) {
+ defer r.Body.Close()
+ var body models.ProfilingStartRequest
+ if err := route.Consumer.Consume(r.Body, &body); err != nil {
+ if err == io.EOF {
+ res = append(res, errors.Required("body", "body"))
+ } else {
+ res = append(res, errors.NewParseError("body", "body", "", err))
+ }
+ } else {
+ // validate body object
+ if err := body.Validate(route.Formats); err != nil {
+ res = append(res, err)
+ }
+
+ if len(res) == 0 {
+ o.Body = &body
+ }
+ }
+ } else {
+ res = append(res, errors.Required("body", "body"))
+ }
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
diff --git a/restapi/operations/admin_api/profiling_start_responses.go b/restapi/operations/admin_api/profiling_start_responses.go
new file mode 100644
index 000000000..bee1e8c03
--- /dev/null
+++ b/restapi/operations/admin_api/profiling_start_responses.go
@@ -0,0 +1,133 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/runtime"
+
+ "github.com/minio/m3/mcs/models"
+)
+
+// ProfilingStartCreatedCode is the HTTP code returned for type ProfilingStartCreated
+const ProfilingStartCreatedCode int = 201
+
+/*ProfilingStartCreated A successful response.
+
+swagger:response profilingStartCreated
+*/
+type ProfilingStartCreated struct {
+
+ /*
+ In: Body
+ */
+ Payload *models.StartProfilingList `json:"body,omitempty"`
+}
+
+// NewProfilingStartCreated creates ProfilingStartCreated with default headers values
+func NewProfilingStartCreated() *ProfilingStartCreated {
+
+ return &ProfilingStartCreated{}
+}
+
+// WithPayload adds the payload to the profiling start created response
+func (o *ProfilingStartCreated) WithPayload(payload *models.StartProfilingList) *ProfilingStartCreated {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the profiling start created response
+func (o *ProfilingStartCreated) SetPayload(payload *models.StartProfilingList) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *ProfilingStartCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(201)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
+
+/*ProfilingStartDefault Generic error response.
+
+swagger:response profilingStartDefault
+*/
+type ProfilingStartDefault struct {
+ _statusCode int
+
+ /*
+ In: Body
+ */
+ Payload *models.Error `json:"body,omitempty"`
+}
+
+// NewProfilingStartDefault creates ProfilingStartDefault with default headers values
+func NewProfilingStartDefault(code int) *ProfilingStartDefault {
+ if code <= 0 {
+ code = 500
+ }
+
+ return &ProfilingStartDefault{
+ _statusCode: code,
+ }
+}
+
+// WithStatusCode adds the status to the profiling start default response
+func (o *ProfilingStartDefault) WithStatusCode(code int) *ProfilingStartDefault {
+ o._statusCode = code
+ return o
+}
+
+// SetStatusCode sets the status to the profiling start default response
+func (o *ProfilingStartDefault) SetStatusCode(code int) {
+ o._statusCode = code
+}
+
+// WithPayload adds the payload to the profiling start default response
+func (o *ProfilingStartDefault) WithPayload(payload *models.Error) *ProfilingStartDefault {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the profiling start default response
+func (o *ProfilingStartDefault) SetPayload(payload *models.Error) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *ProfilingStartDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(o._statusCode)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
diff --git a/restapi/operations/admin_api/profiling_start_urlbuilder.go b/restapi/operations/admin_api/profiling_start_urlbuilder.go
new file mode 100644
index 000000000..89b9c72a4
--- /dev/null
+++ b/restapi/operations/admin_api/profiling_start_urlbuilder.go
@@ -0,0 +1,101 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "errors"
+ "net/url"
+ golangswaggerpaths "path"
+)
+
+// ProfilingStartURL generates an URL for the profiling start operation
+type ProfilingStartURL struct {
+ _basePath string
+}
+
+// WithBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *ProfilingStartURL) WithBasePath(bp string) *ProfilingStartURL {
+ o.SetBasePath(bp)
+ return o
+}
+
+// SetBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *ProfilingStartURL) SetBasePath(bp string) {
+ o._basePath = bp
+}
+
+// Build a url path and query string
+func (o *ProfilingStartURL) Build() (*url.URL, error) {
+ var _result url.URL
+
+ var _path = "/api/v1/profiling/start"
+
+ _basePath := o._basePath
+ _result.Path = golangswaggerpaths.Join(_basePath, _path)
+
+ return &_result, nil
+}
+
+// Must is a helper function to panic when the url builder returns an error
+func (o *ProfilingStartURL) Must(u *url.URL, err error) *url.URL {
+ if err != nil {
+ panic(err)
+ }
+ if u == nil {
+ panic("url can't be nil")
+ }
+ return u
+}
+
+// String returns the string representation of the path with query string
+func (o *ProfilingStartURL) String() string {
+ return o.Must(o.Build()).String()
+}
+
+// BuildFull builds a full url with scheme, host, path and query string
+func (o *ProfilingStartURL) BuildFull(scheme, host string) (*url.URL, error) {
+ if scheme == "" {
+ return nil, errors.New("scheme is required for a full url on ProfilingStartURL")
+ }
+ if host == "" {
+ return nil, errors.New("host is required for a full url on ProfilingStartURL")
+ }
+
+ base, err := o.Build()
+ if err != nil {
+ return nil, err
+ }
+
+ base.Scheme = scheme
+ base.Host = host
+ return base, nil
+}
+
+// StringFull returns the string representation of a complete url
+func (o *ProfilingStartURL) StringFull(scheme, host string) string {
+ return o.Must(o.BuildFull(scheme, host)).String()
+}
diff --git a/restapi/operations/admin_api/profiling_stop.go b/restapi/operations/admin_api/profiling_stop.go
new file mode 100644
index 000000000..2d0677be7
--- /dev/null
+++ b/restapi/operations/admin_api/profiling_stop.go
@@ -0,0 +1,88 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/runtime/middleware"
+)
+
+// ProfilingStopHandlerFunc turns a function with the right signature into a profiling stop handler
+type ProfilingStopHandlerFunc func(ProfilingStopParams, interface{}) middleware.Responder
+
+// Handle executing the request and returning a response
+func (fn ProfilingStopHandlerFunc) Handle(params ProfilingStopParams, principal interface{}) middleware.Responder {
+ return fn(params, principal)
+}
+
+// ProfilingStopHandler interface for that can handle valid profiling stop params
+type ProfilingStopHandler interface {
+ Handle(ProfilingStopParams, interface{}) middleware.Responder
+}
+
+// NewProfilingStop creates a new http.Handler for the profiling stop operation
+func NewProfilingStop(ctx *middleware.Context, handler ProfilingStopHandler) *ProfilingStop {
+ return &ProfilingStop{Context: ctx, Handler: handler}
+}
+
+/*ProfilingStop swagger:route POST /api/v1/profiling/stop AdminAPI profilingStop
+
+Stop and download profile data
+
+*/
+type ProfilingStop struct {
+ Context *middleware.Context
+ Handler ProfilingStopHandler
+}
+
+func (o *ProfilingStop) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
+ route, rCtx, _ := o.Context.RouteInfo(r)
+ if rCtx != nil {
+ r = rCtx
+ }
+ var Params = NewProfilingStopParams()
+
+ uprinc, aCtx, err := o.Context.Authorize(r, route)
+ if err != nil {
+ o.Context.Respond(rw, r, route.Produces, route, err)
+ return
+ }
+ if aCtx != nil {
+ r = aCtx
+ }
+ var principal interface{}
+ if uprinc != nil {
+ principal = uprinc
+ }
+
+ if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
+ o.Context.Respond(rw, r, route.Produces, route, err)
+ return
+ }
+
+ res := o.Handler.Handle(Params, principal) // actually handle the request
+
+ o.Context.Respond(rw, r, route.Produces, route, res)
+
+}
diff --git a/restapi/operations/admin_api/profiling_stop_parameters.go b/restapi/operations/admin_api/profiling_stop_parameters.go
new file mode 100644
index 000000000..3330f9197
--- /dev/null
+++ b/restapi/operations/admin_api/profiling_stop_parameters.go
@@ -0,0 +1,62 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "net/http"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/runtime/middleware"
+)
+
+// NewProfilingStopParams creates a new ProfilingStopParams object
+// no default values defined in spec.
+func NewProfilingStopParams() ProfilingStopParams {
+
+ return ProfilingStopParams{}
+}
+
+// ProfilingStopParams contains all the bound params for the profiling stop operation
+// typically these are obtained from a http.Request
+//
+// swagger:parameters ProfilingStop
+type ProfilingStopParams struct {
+
+ // HTTP Request Object
+ HTTPRequest *http.Request `json:"-"`
+}
+
+// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
+// for simple values it will use straight method calls.
+//
+// To ensure default values, the struct must have been initialized with NewProfilingStopParams() beforehand.
+func (o *ProfilingStopParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
+ var res []error
+
+ o.HTTPRequest = r
+
+ if len(res) > 0 {
+ return errors.CompositeValidationError(res...)
+ }
+ return nil
+}
diff --git a/restapi/operations/admin_api/profiling_stop_responses.go b/restapi/operations/admin_api/profiling_stop_responses.go
new file mode 100644
index 000000000..8ad300f1b
--- /dev/null
+++ b/restapi/operations/admin_api/profiling_stop_responses.go
@@ -0,0 +1,132 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the swagger generate command
+
+import (
+ "io"
+ "net/http"
+
+ "github.com/go-openapi/runtime"
+
+ "github.com/minio/m3/mcs/models"
+)
+
+// ProfilingStopCreatedCode is the HTTP code returned for type ProfilingStopCreated
+const ProfilingStopCreatedCode int = 201
+
+/*ProfilingStopCreated A successful response.
+
+swagger:response profilingStopCreated
+*/
+type ProfilingStopCreated struct {
+
+ /*
+ In: Body
+ */
+ Payload io.ReadCloser `json:"body,omitempty"`
+}
+
+// NewProfilingStopCreated creates ProfilingStopCreated with default headers values
+func NewProfilingStopCreated() *ProfilingStopCreated {
+
+ return &ProfilingStopCreated{}
+}
+
+// WithPayload adds the payload to the profiling stop created response
+func (o *ProfilingStopCreated) WithPayload(payload io.ReadCloser) *ProfilingStopCreated {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the profiling stop created response
+func (o *ProfilingStopCreated) SetPayload(payload io.ReadCloser) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *ProfilingStopCreated) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(201)
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+}
+
+/*ProfilingStopDefault Generic error response.
+
+swagger:response profilingStopDefault
+*/
+type ProfilingStopDefault struct {
+ _statusCode int
+
+ /*
+ In: Body
+ */
+ Payload *models.Error `json:"body,omitempty"`
+}
+
+// NewProfilingStopDefault creates ProfilingStopDefault with default headers values
+func NewProfilingStopDefault(code int) *ProfilingStopDefault {
+ if code <= 0 {
+ code = 500
+ }
+
+ return &ProfilingStopDefault{
+ _statusCode: code,
+ }
+}
+
+// WithStatusCode adds the status to the profiling stop default response
+func (o *ProfilingStopDefault) WithStatusCode(code int) *ProfilingStopDefault {
+ o._statusCode = code
+ return o
+}
+
+// SetStatusCode sets the status to the profiling stop default response
+func (o *ProfilingStopDefault) SetStatusCode(code int) {
+ o._statusCode = code
+}
+
+// WithPayload adds the payload to the profiling stop default response
+func (o *ProfilingStopDefault) WithPayload(payload *models.Error) *ProfilingStopDefault {
+ o.Payload = payload
+ return o
+}
+
+// SetPayload sets the payload to the profiling stop default response
+func (o *ProfilingStopDefault) SetPayload(payload *models.Error) {
+ o.Payload = payload
+}
+
+// WriteResponse to the client
+func (o *ProfilingStopDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
+
+ rw.WriteHeader(o._statusCode)
+ if o.Payload != nil {
+ payload := o.Payload
+ if err := producer.Produce(rw, payload); err != nil {
+ panic(err) // let the recovery middleware deal with this
+ }
+ }
+}
diff --git a/restapi/operations/admin_api/profiling_stop_urlbuilder.go b/restapi/operations/admin_api/profiling_stop_urlbuilder.go
new file mode 100644
index 000000000..44cab739a
--- /dev/null
+++ b/restapi/operations/admin_api/profiling_stop_urlbuilder.go
@@ -0,0 +1,101 @@
+// Code generated by go-swagger; DO NOT EDIT.
+
+// This file is part of MinIO Console Server
+// Copyright (c) 2020 MinIO, Inc.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+//
+
+package admin_api
+
+// This file was generated by the swagger tool.
+// Editing this file might prove futile when you re-run the generate command
+
+import (
+ "errors"
+ "net/url"
+ golangswaggerpaths "path"
+)
+
+// ProfilingStopURL generates an URL for the profiling stop operation
+type ProfilingStopURL struct {
+ _basePath string
+}
+
+// WithBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *ProfilingStopURL) WithBasePath(bp string) *ProfilingStopURL {
+ o.SetBasePath(bp)
+ return o
+}
+
+// SetBasePath sets the base path for this url builder, only required when it's different from the
+// base path specified in the swagger spec.
+// When the value of the base path is an empty string
+func (o *ProfilingStopURL) SetBasePath(bp string) {
+ o._basePath = bp
+}
+
+// Build a url path and query string
+func (o *ProfilingStopURL) Build() (*url.URL, error) {
+ var _result url.URL
+
+ var _path = "/api/v1/profiling/stop"
+
+ _basePath := o._basePath
+ _result.Path = golangswaggerpaths.Join(_basePath, _path)
+
+ return &_result, nil
+}
+
+// Must is a helper function to panic when the url builder returns an error
+func (o *ProfilingStopURL) Must(u *url.URL, err error) *url.URL {
+ if err != nil {
+ panic(err)
+ }
+ if u == nil {
+ panic("url can't be nil")
+ }
+ return u
+}
+
+// String returns the string representation of the path with query string
+func (o *ProfilingStopURL) String() string {
+ return o.Must(o.Build()).String()
+}
+
+// BuildFull builds a full url with scheme, host, path and query string
+func (o *ProfilingStopURL) BuildFull(scheme, host string) (*url.URL, error) {
+ if scheme == "" {
+ return nil, errors.New("scheme is required for a full url on ProfilingStopURL")
+ }
+ if host == "" {
+ return nil, errors.New("host is required for a full url on ProfilingStopURL")
+ }
+
+ base, err := o.Build()
+ if err != nil {
+ return nil, err
+ }
+
+ base.Scheme = scheme
+ base.Host = host
+ return base, nil
+}
+
+// StringFull returns the string representation of a complete url
+func (o *ProfilingStopURL) StringFull(scheme, host string) string {
+ return o.Must(o.BuildFull(scheme, host)).String()
+}
diff --git a/restapi/operations/mcs_api.go b/restapi/operations/mcs_api.go
index dcfccdb52..18bf61bac 100644
--- a/restapi/operations/mcs_api.go
+++ b/restapi/operations/mcs_api.go
@@ -59,6 +59,7 @@ func NewMcsAPI(spec *loads.Document) *McsAPI {
JSONConsumer: runtime.JSONConsumer(),
+ BinProducer: runtime.ByteStreamProducer(),
JSONProducer: runtime.JSONProducer(),
AdminAPIAddGroupHandler: admin_api.AddGroupHandlerFunc(func(params admin_api.AddGroupParams, principal interface{}) middleware.Responder {
@@ -115,6 +116,12 @@ func NewMcsAPI(spec *loads.Document) *McsAPI {
AdminAPIPolicyInfoHandler: admin_api.PolicyInfoHandlerFunc(func(params admin_api.PolicyInfoParams, principal interface{}) middleware.Responder {
return middleware.NotImplemented("operation admin_api.PolicyInfo has not yet been implemented")
}),
+ AdminAPIProfilingStartHandler: admin_api.ProfilingStartHandlerFunc(func(params admin_api.ProfilingStartParams, principal interface{}) middleware.Responder {
+ return middleware.NotImplemented("operation admin_api.ProfilingStart has not yet been implemented")
+ }),
+ AdminAPIProfilingStopHandler: admin_api.ProfilingStopHandlerFunc(func(params admin_api.ProfilingStopParams, principal interface{}) middleware.Responder {
+ return middleware.NotImplemented("operation admin_api.ProfilingStop has not yet been implemented")
+ }),
AdminAPIRemoveGroupHandler: admin_api.RemoveGroupHandlerFunc(func(params admin_api.RemoveGroupParams, principal interface{}) middleware.Responder {
return middleware.NotImplemented("operation admin_api.RemoveGroup has not yet been implemented")
}),
@@ -168,6 +175,9 @@ type McsAPI struct {
// - application/json
JSONConsumer runtime.Consumer
+ // BinProducer registers a producer for the following mime types:
+ // - application/octet-stream
+ BinProducer runtime.Producer
// JSONProducer registers a producer for the following mime types:
// - application/json
JSONProducer runtime.Producer
@@ -215,6 +225,10 @@ type McsAPI struct {
UserAPIMakeBucketHandler user_api.MakeBucketHandler
// AdminAPIPolicyInfoHandler sets the operation handler for the policy info operation
AdminAPIPolicyInfoHandler admin_api.PolicyInfoHandler
+ // AdminAPIProfilingStartHandler sets the operation handler for the profiling start operation
+ AdminAPIProfilingStartHandler admin_api.ProfilingStartHandler
+ // AdminAPIProfilingStopHandler sets the operation handler for the profiling stop operation
+ AdminAPIProfilingStopHandler admin_api.ProfilingStopHandler
// AdminAPIRemoveGroupHandler sets the operation handler for the remove group operation
AdminAPIRemoveGroupHandler admin_api.RemoveGroupHandler
// AdminAPIRemovePolicyHandler sets the operation handler for the remove policy operation
@@ -289,6 +303,9 @@ func (o *McsAPI) Validate() error {
unregistered = append(unregistered, "JSONConsumer")
}
+ if o.BinProducer == nil {
+ unregistered = append(unregistered, "BinProducer")
+ }
if o.JSONProducer == nil {
unregistered = append(unregistered, "JSONProducer")
}
@@ -351,6 +368,12 @@ func (o *McsAPI) Validate() error {
if o.AdminAPIPolicyInfoHandler == nil {
unregistered = append(unregistered, "admin_api.PolicyInfoHandler")
}
+ if o.AdminAPIProfilingStartHandler == nil {
+ unregistered = append(unregistered, "admin_api.ProfilingStartHandler")
+ }
+ if o.AdminAPIProfilingStopHandler == nil {
+ unregistered = append(unregistered, "admin_api.ProfilingStopHandler")
+ }
if o.AdminAPIRemoveGroupHandler == nil {
unregistered = append(unregistered, "admin_api.RemoveGroupHandler")
}
@@ -423,6 +446,8 @@ func (o *McsAPI) ProducersFor(mediaTypes []string) map[string]runtime.Producer {
result := make(map[string]runtime.Producer, len(mediaTypes))
for _, mt := range mediaTypes {
switch mt {
+ case "application/octet-stream":
+ result["application/octet-stream"] = o.BinProducer
case "application/json":
result["application/json"] = o.JSONProducer
}
@@ -537,6 +562,14 @@ func (o *McsAPI) initHandlerCache() {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/api/v1/policies/{name}"] = admin_api.NewPolicyInfo(o.context, o.AdminAPIPolicyInfoHandler)
+ if o.handlers["POST"] == nil {
+ o.handlers["POST"] = make(map[string]http.Handler)
+ }
+ o.handlers["POST"]["/api/v1/profiling/start"] = admin_api.NewProfilingStart(o.context, o.AdminAPIProfilingStartHandler)
+ if o.handlers["POST"] == nil {
+ o.handlers["POST"] = make(map[string]http.Handler)
+ }
+ o.handlers["POST"]["/api/v1/profiling/stop"] = admin_api.NewProfilingStop(o.context, o.AdminAPIProfilingStopHandler)
if o.handlers["DELETE"] == nil {
o.handlers["DELETE"] = make(map[string]http.Handler)
}
diff --git a/restapi/user_login.go b/restapi/user_login.go
index 79e04d72c..5d4a0c7e6 100644
--- a/restapi/user_login.go
+++ b/restapi/user_login.go
@@ -69,7 +69,6 @@ func login(mc McCmd, accessKey, secretKey *string) (*string, error) {
// Probe the credentials
cfg, pErr := mc.BuildS3Config(getMinIOServer(), *accessKey, *secretKey, "", "auto")
if pErr != nil {
- log.Println(pErr)
return nil, ErrInvalidCredentials
}
// if we made it here, the credentials work, generate a session
diff --git a/swagger.yml b/swagger.yml
index d038a650a..1a5e4c226 100644
--- a/swagger.yml
+++ b/swagger.yml
@@ -270,7 +270,7 @@ paths:
tags:
- AdminAPI
delete:
- summary: Remove group
+ summary: Remove group
operationId: RemoveGroup
parameters:
- name: name
@@ -536,6 +536,44 @@ paths:
security: []
tags:
- UserAPI
+ /api/v1/profiling/start:
+ post:
+ summary: Start recording profile data
+ operationId: ProfilingStart
+ parameters:
+ - name: body
+ in: body
+ required: true
+ schema:
+ $ref: '#/definitions/profilingStartRequest'
+ responses:
+ 201:
+ description: A successful response.
+ schema:
+ $ref: '#/definitions/startProfilingList'
+ default:
+ description: Generic error response.
+ schema:
+ $ref: "#/definitions/error"
+ tags:
+ - AdminAPI
+ /api/v1/profiling/stop:
+ post:
+ summary: Stop and download profile data
+ operationId: ProfilingStop
+ produces:
+ - application/octet-stream
+ responses:
+ 201:
+ description: A successful response.
+ schema:
+ type: file
+ default:
+ description: Generic error response.
+ schema:
+ $ref: "#/definitions/error"
+ tags:
+ - AdminAPI
definitions:
bucketAccess:
type: string
@@ -819,7 +857,7 @@ definitions:
- access
properties:
access:
- $ref: "#/definitions/bucketAccess"
+ $ref: "#/definitions/bucketAccess"
loginDetails:
type: object
properties:
@@ -846,3 +884,40 @@ definitions:
# Structure that holds the `Bearer {TOKEN}` present on authenticated requests
principal:
type: string
+ startProfilingItem:
+ type: object
+ properties:
+ nodeName:
+ type: string
+ success:
+ type: boolean
+ error:
+ type: string
+ startProfilingList:
+ type: object
+ properties:
+ total:
+ type: integer
+ format: int64
+ title: number of start results
+ startResults:
+ type: array
+ items:
+ $ref: "#/definitions/startProfilingItem"
+ profilerType:
+ type: string
+ enum:
+ - cpu
+ - mem
+ - block
+ - mutex
+ - trace
+ - threads
+ - goroutines
+ profilingStartRequest:
+ type: object
+ required:
+ - type
+ properties:
+ type:
+ $ref: "#/definitions/profilerType"
\ No newline at end of file