admin: Add missing madmin examples and API docs. (#3483)

This commit is contained in:
Harshavardhana 2016-12-20 18:49:48 -08:00 committed by GitHub
parent e7b4e4e105
commit f57f773189
11 changed files with 440 additions and 51 deletions

View file

@ -25,6 +25,12 @@ const (
minioAdminOpHeader = "X-Minio-Operation"
)
// ServiceStatusHandler - GET /?service
// HTTP header x-minio-operation: status
// ----------
// This implementation of the GET operation fetches server status information.
// provides total disk space available to use, online disks, offline disks and
// quorum threshold.
func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *http.Request) {
adminAPIErr := checkRequestAuthType(r, "", "", "")
if adminAPIErr != ErrNone {
@ -41,6 +47,12 @@ func (adminAPI adminAPIHandlers) ServiceStatusHandler(w http.ResponseWriter, r *
writeSuccessResponse(w, jsonBytes)
}
// ServiceStopHandler - POST /?service
// HTTP header x-minio-operation: stop
// ----------
// This implementation of the POST operation stops minio server gracefully,
// in a distributed setup stops all the servers in the cluster. Body sent
// if any on client request is ignored.
func (adminAPI adminAPIHandlers) ServiceStopHandler(w http.ResponseWriter, r *http.Request) {
adminAPIErr := checkRequestAuthType(r, "", "", "")
if adminAPIErr != ErrNone {
@ -52,6 +64,12 @@ func (adminAPI adminAPIHandlers) ServiceStopHandler(w http.ResponseWriter, r *ht
sendServiceCmd(globalAdminPeers, serviceStop)
}
// ServiceRestartHandler - POST /?service
// HTTP header x-minio-operation: restart
// ----------
// This implementation of the POST operation restarts minio server gracefully,
// in a distributed setup restarts all the servers in the cluster. Body sent
// if any on client request is ignored.
func (adminAPI adminAPIHandlers) ServiceRestartHandler(w http.ResponseWriter, r *http.Request) {
adminAPIErr := checkRequestAuthType(r, "", "", "")
if adminAPIErr != ErrNone {

View file

@ -26,7 +26,7 @@ const (
Unknown BackendType = iota
// Filesystem backend.
FS
// Multi disk single node XL backend.
// Multi disk XL (single, distributed) backend.
XL
// Add your own backend.
)

135
pkg/madmin/API.md Normal file
View file

@ -0,0 +1,135 @@
# Golang Admin Client API Reference [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Minio/minio?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Initialize Minio Admin Client object.
## Minio
```go
package main
import (
"fmt"
"github.com/minio/minio/pkg/madmin"
)
func main() {
// Use a secure connection.
ssl := true
// Initialize minio client object.
mdmClnt, err := madmin.New("your-minio.example.com:9000", "YOUR-ACCESSKEYID", "YOUR-SECRETKEY", ssl)
if err != nil {
fmt.Println(err)
return
}
// Fetch service status.
st, err := mdmClnt.ServiceStatus()
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%#v\n", st)
}
```
| Service operations|LockInfo operations|Healing operations|
|:---|:---|:---|
|[`ServiceStatus`](#ServiceStatus)| | |
|[`ServiceStop`](#ServiceStop)| | |
|[`ServiceRestart`](#ServiceRestart)| | |
## 1. Constructor
<a name="Minio"></a>
### New(endpoint string, accessKeyID string, secretAccessKey string, ssl bool) (*AdminClient, error)
Initializes a new admin client object.
__Parameters__
|Param |Type |Description |
|:---|:---| :---|
|`endpoint` | _string_ |Minio endpoint. |
|`accessKeyID` |_string_ | Access key for the object storage endpoint. |
|`secretAccessKey` | _string_ |Secret key for the object storage endpoint. |
|`ssl` | _bool_ | Set this value to 'true' to enable secure (HTTPS) access. |
## 2. Service operations
<a name="ServiceStatus"></a>
### ServiceStatus() (ServiceStatusMetadata, error)
Fetch service status, replies disk space used, backend type and total disks offline/online (XL).
| Param | Type | Description |
|---|---|---|
|`serviceStatus` | _ServiceStatusMetadata_ | Represents current server status info in following format: |
| Param | Type | Description |
|---|---|---|
|`st.Total` | _int64_ | Total disk space. |
|`st.Free` | _int64_ | Free disk space. |
|`st.Backend`| _struct{}_ | Represents backend type embedded structure. |
| Param | Type | Description |
|---|---|---|
|`backend.Type` | _BackendType_ | Type of backend used by the server currently only FS or XL. |
|`backend.OnlineDisks`| _int_ | Total number of disks online (only applies to XL backend), is empty for FS. |
|`backend.OfflineDisks` | _int_ | Total number of disks offline (only applies to XL backend), is empty for FS. |
|`backend.ReadQuorum` | _int_ | Current total read quorum threshold before reads will be unavailable, is empty for FS. |
|`backend.WriteQuorum` | _int_ | Current total write quorum threshold before writes will be unavailable, is empty for FS. |
__Example__
```go
st, err := madmClnt.ServiceStatus()
if err != nil {
log.Fatalln(err)
}
log.Printf("%#v\n", st)
```
<a name="ServiceStop"></a>
### ServiceStop() (error)
If successful shuts down the running minio service, for distributed setup stops all remote minio servers.
__Example__
```go
st, err := madmClnt.ServiceStop()
if err != nil {
log.Fatalln(err)
}
log.Printf("Succes")
```
<a name="ServiceRestart"></a>
### ServiceRestart() (error)
If successful restarts the running minio service, for distributed setup restarts all remote minio servers.
__Example__
```go
st, err := madmClnt.ServiceRestart()
if err != nil {
log.Fatalln(err)
}
log.Printf("Succes")
```

122
pkg/madmin/README.md Normal file
View file

@ -0,0 +1,122 @@
# Minio Admin Library. [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Minio/minio?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
The Minio Admin Golang Client SDK provides APIs to manage Minio services.
This quickstart guide will show you how to install the Minio Admin client SDK, connect to Minio admin service, and provide a walkthrough of a simple file uploader.
This document assumes that you have a working [Golang setup](https://docs.minio.io/docs/how-to-install-golang).
## Download from Github
```sh
go get -u github.com/minio/minio/pkg/madmin
```
## Initialize Minio Admin Client
You need four items to connect to Minio admin services.
| Parameter | Description|
| :--- | :--- |
| endpoint | URL to object storage service. |
| accessKeyID | Access key is the user ID that uniquely identifies your account. |
| secretAccessKey | Secret key is the password to your account. |
| secure | Set this value to 'true' to enable secure (HTTPS) access. |
```go
package main
import (
"github.com/minio/minio/pkg/madmin"
"log"
)
func main() {
endpoint := "your-minio.example.com:9000"
accessKeyID := "YOUR-ACCESSKEYID"
secretAccessKey := "YOUR-SECRETKEY"
useSSL := true
// Initialize minio admin client object.
madmClnt, err := madmin.New(endpoint, accessKeyID, secretAccessKey, useSSL)
if err != nil {
log.Fatalln(err)
}
log.Println("%v", madmClnt) // Minio admin client is now setup
```
## Quick Start Example - Service Status.
This example program connects to minio server, gets the current disk status.
We will use the Minio server running at [https://your-minio.example.com:9000](https://your-minio.example.com:9000) in this example. Feel free to use this service for testing and development. Access credentials shown in this example are open to the public.
#### ServiceStatus.go
```go
package main
import (
"log"
"github.com/minio/minio/pkg/madmin"
)
func main() {
endpoint := "your-minio.example.com:9000"
accessKeyID := "YOUR-ACCESSKEYID"
secretAccessKey := "YOUR-SECRETKEY"
useSSL := true
// Initialize minio admin client.
mdmClnt, err := madmin.New(endpoint, accessKeyID, secretAccessKey, useSSL)
if err != nil {
log.Fatalln(err)
}
st, err := madmClnt.ServiceStatus()
if err != nil {
log.Fatalln(err)
}
log.Printf("%#v\n", st)
}
```
#### Run ServiceStatus
```sh
go run service-status.go
2016/12/20 16:46:01 madmin.ServiceStatusMetadata{Total:177038229504, Free:120365559808, Backend:struct { Type madmin.BackendType; OnlineDisks int; OfflineDisks int; ReadQuorum int; WriteQuorum int }{Type:1, OnlineDisks:0, OfflineDisks:0, ReadQuorum:0, WriteQuorum:0}}
```
## API Reference
### API Reference : Service Operations
* [`ServiceStatus`](./API.md#ServiceStatus)
* [`ServiceStop`](./API.md#ServiceStop)
* [`ServiceRestart`](./API.md#ServiceRestart)
## Full Examples
#### Full Examples : Service Operations
* [service-status.go](https://github.com/minio/minio/blob/master/pkg/madmin/examples/service-status.go)
* [service-stop.go](https://github.com/minio/minio/blob/master/pkg/madmin/examples/service-stop.go)
* [service-restart.go](https://github.com/minio/minio/blob/master/pkg/madmin/examples/service-restart.go)
## Contribute
[Contributors Guide](https://github.com/minio/minio/blob/master/CONTRIBUTING.md)

View file

@ -36,8 +36,8 @@ import (
"github.com/minio/minio-go/pkg/s3utils"
)
// Client implements Amazon S3 compatible methods.
type Client struct {
// AdminClient implements Amazon S3 compatible methods.
type AdminClient struct {
/// Standard options.
// AccessKeyID required for authorized requests.
@ -82,9 +82,8 @@ const (
libraryUserAgent = libraryUserAgentPrefix + libraryName + "/" + libraryVersion
)
// New - instantiate minio client Client, adds automatic verification
// of signature.
func New(endpoint string, accessKeyID, secretAccessKey string, secure bool) (*Client, error) {
// New - instantiate minio client Client, adds automatic verification of signature.
func New(endpoint string, accessKeyID, secretAccessKey string, secure bool) (*AdminClient, error) {
clnt, err := privateNew(endpoint, accessKeyID, secretAccessKey, secure)
if err != nil {
return nil, err
@ -104,7 +103,7 @@ func redirectHeaders(req *http.Request, via []*http.Request) error {
return nil
}
func privateNew(endpoint, accessKeyID, secretAccessKey string, secure bool) (*Client, error) {
func privateNew(endpoint, accessKeyID, secretAccessKey string, secure bool) (*AdminClient, error) {
// construct endpoint.
endpointURL, err := getEndpointURL(endpoint, secure)
if err != nil {
@ -112,20 +111,18 @@ func privateNew(endpoint, accessKeyID, secretAccessKey string, secure bool) (*Cl
}
// instantiate new Client.
clnt := new(Client)
clnt.accessKeyID = accessKeyID
clnt.secretAccessKey = secretAccessKey
// Remember whether we are using https or not
clnt.secure = secure
// Save endpoint URL, user agent for future uses.
clnt.endpointURL = *endpointURL
// Instantiate http client and bucket location cache.
clnt.httpClient = &http.Client{
Transport: http.DefaultTransport,
CheckRedirect: redirectHeaders,
clnt := &AdminClient{
accessKeyID: accessKeyID,
secretAccessKey: secretAccessKey,
// Remember whether we are using https or not
secure: secure,
// Save endpoint URL, user agent for future uses.
endpointURL: *endpointURL,
// Instantiate http client and bucket location cache.
httpClient: &http.Client{
Transport: http.DefaultTransport,
CheckRedirect: redirectHeaders,
},
}
// Return.
@ -133,7 +130,7 @@ func privateNew(endpoint, accessKeyID, secretAccessKey string, secure bool) (*Cl
}
// SetAppInfo - add application details to user agent.
func (c *Client) SetAppInfo(appName string, appVersion string) {
func (c *AdminClient) SetAppInfo(appName string, appVersion string) {
// if app name and version is not set, we do not a new user
// agent.
if appName != "" && appVersion != "" {
@ -147,7 +144,7 @@ func (c *Client) SetAppInfo(appName string, appVersion string) {
}
// SetCustomTransport - set new custom transport.
func (c *Client) SetCustomTransport(customHTTPTransport http.RoundTripper) {
func (c *AdminClient) SetCustomTransport(customHTTPTransport http.RoundTripper) {
// Set this to override default transport
// ``http.DefaultTransport``.
//
@ -168,7 +165,7 @@ func (c *Client) SetCustomTransport(customHTTPTransport http.RoundTripper) {
}
// TraceOn - enable HTTP tracing.
func (c *Client) TraceOn(outputStream io.Writer) {
func (c *AdminClient) TraceOn(outputStream io.Writer) {
// if outputStream is nil then default to os.Stdout.
if outputStream == nil {
outputStream = os.Stdout
@ -181,7 +178,7 @@ func (c *Client) TraceOn(outputStream io.Writer) {
}
// TraceOff - disable HTTP tracing.
func (c *Client) TraceOff() {
func (c *AdminClient) TraceOff() {
// Disable tracing.
c.isTraceEnabled = false
}
@ -199,7 +196,7 @@ type requestData struct {
}
// Filter out signature value from Authorization header.
func (c Client) filterSignature(req *http.Request) {
func (c AdminClient) filterSignature(req *http.Request) {
/// Signature V4 authorization header.
// Save the original auth.
@ -219,7 +216,7 @@ func (c Client) filterSignature(req *http.Request) {
}
// dumpHTTP - dump HTTP request and response.
func (c Client) dumpHTTP(req *http.Request, resp *http.Response) error {
func (c AdminClient) dumpHTTP(req *http.Request, resp *http.Response) error {
// Starts http dump.
_, err := fmt.Fprintln(c.traceOutput, "---------START-HTTP---------")
if err != nil {
@ -288,7 +285,7 @@ func (c Client) dumpHTTP(req *http.Request, resp *http.Response) error {
}
// do - execute http request.
func (c Client) do(req *http.Request) (*http.Response, error) {
func (c AdminClient) do(req *http.Request) (*http.Response, error) {
var resp *http.Response
var err error
// Do the request in a loop in case of 307 http is met since golang still doesn't
@ -346,7 +343,7 @@ var successStatus = []int{
// executeMethod - instantiates a given method, and retries the
// request upon any error up to maxRetries attempts in a binomially
// delayed manner using a standard back off algorithm.
func (c Client) executeMethod(method string, reqData requestData) (res *http.Response, err error) {
func (c AdminClient) executeMethod(method string, reqData requestData) (res *http.Response, err error) {
// Create a done channel to control 'ListObjects' go routine.
doneCh := make(chan struct{}, 1)
@ -391,7 +388,7 @@ func (c Client) executeMethod(method string, reqData requestData) (res *http.Res
}
// set User agent.
func (c Client) setUserAgent(req *http.Request) {
func (c AdminClient) setUserAgent(req *http.Request) {
req.Header.Set("User-Agent", libraryUserAgent)
if c.appInfo.appName != "" && c.appInfo.appVersion != "" {
req.Header.Set("User-Agent", libraryUserAgent+" "+c.appInfo.appName+"/"+c.appInfo.appVersion)
@ -399,7 +396,7 @@ func (c Client) setUserAgent(req *http.Request) {
}
// newRequest - instantiate a new HTTP request for a given method.
func (c Client) newRequest(method string, reqData requestData) (req *http.Request, err error) {
func (c AdminClient) newRequest(method string, reqData requestData) (req *http.Request, err error) {
// If no method is supplied default to 'POST'.
if method == "" {
method = "POST"
@ -461,7 +458,7 @@ func (c Client) newRequest(method string, reqData requestData) (req *http.Reques
}
// makeTargetURL make a new target url.
func (c Client) makeTargetURL(queryValues url.Values) (*url.URL, error) {
func (c AdminClient) makeTargetURL(queryValues url.Values) (*url.URL, error) {
host := c.endpointURL.Host
scheme := c.endpointURL.Scheme

View file

@ -18,7 +18,15 @@
// Package madmin_test
package madmin_test
import "testing"
import (
"testing"
func TestMAdminClient(t *testing.T) {
"github.com/minio/minio/pkg/madmin"
)
func TestMinioAdminClient(t *testing.T) {
_, err := madmin.New("localhost:9000", "food", "food123", true)
if err != nil {
t.Fatal(err)
}
}

View file

@ -16,4 +16,10 @@
package madmin
const unsignedPayload = "UNSIGNED-PAYLOAD"
const (
// Unsigned payload.
unsignedPayload = "UNSIGNED-PAYLOAD"
// Admin operation header.
minioAdminOpHeader = "X-Minio-Operation"
)

View file

@ -1,3 +1,5 @@
// +build ignore
/*
* Minio Cloud Storage, (C) 2016 Minio, Inc.
*
@ -15,23 +17,30 @@
*
*/
package madmin
package main
const (
minioAdminOpHeader = "X-Minio-Operation"
import (
"log"
"github.com/minio/minio/pkg/madmin"
)
// AdminClient - interface to Minio Management API
type AdminClient struct {
client *Client
}
func main() {
// Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY are
// dummy values, please replace them with original values.
// NewAdminClient - create new Management client
func NewAdminClient(addr string, access string, secret string, secure bool) (*AdminClient, error) {
client, err := New(addr, access, secret, secure)
// Requests are always secure (HTTPS) by default. Set secure=false to enable insecure (HTTP) access.
// This boolean value is the last argument for New().
// New returns an Minio Admin client object.
madmClnt, err := madmin.New("your-minio.example.com:9000", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", true)
if err != nil {
return nil, err
log.Fatalln(err)
}
return &AdminClient{client: client}, nil
err = madmClnt.ServiceRestart()
if err != nil {
log.Fatalln(err)
}
log.Println("Success")
}

View file

@ -0,0 +1,46 @@
// +build ignore
/*
* Minio Cloud Storage, (C) 2016 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package main
import (
"log"
"github.com/minio/minio/pkg/madmin"
)
func main() {
// Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY and my-bucketname are
// dummy values, please replace them with original values.
// Requests are always secure (HTTPS) by default. Set secure=false to enable insecure (HTTP) access.
// This boolean value is the last argument for New().
// New returns an Minio Admin client object.
madmClnt, err := madmin.New("your-minio.example.com:9000", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", true)
if err != nil {
log.Fatalln(err)
}
st, err := madmClnt.ServiceStatus()
if err != nil {
log.Fatalln(err)
}
log.Println(st)
}

View file

@ -0,0 +1,46 @@
// +build ignore
/*
* Minio Cloud Storage, (C) 2016 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package main
import (
"log"
"github.com/minio/minio/pkg/madmin"
)
func main() {
// Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY and my-bucketname are
// dummy values, please replace them with original values.
// Requests are always secure (HTTPS) by default. Set secure=false to enable insecure (HTTP) access.
// This boolean value is the last argument for New().
// New returns an Minio Admin client object.
madmClnt, err := madmin.New("your-minio.example.com:9000", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", true)
if err != nil {
log.Fatalln(err)
}
err = madmClnt.ServiceStop()
if err != nil {
log.Fatalln(err)
}
log.Println("Success")
}

View file

@ -33,8 +33,9 @@ const (
Unknown BackendType = iota
// Filesystem backend.
FS
// Multi disk single node XL backend.
// Multi disk XL (single, distributed) backend.
XL
// Add your own backend.
)
@ -48,6 +49,7 @@ type ServiceStatusMetadata struct {
Backend struct {
// Represents various backend types, currently on FS and XL.
Type BackendType
// Following fields are only meaningful if BackendType is XL.
OnlineDisks int // Online disks during server startup.
OfflineDisks int // Offline disks during server startup.
@ -67,7 +69,7 @@ func (adm *AdminClient) ServiceStatus() (ServiceStatusMetadata, error) {
reqData.customHeaders.Set(minioAdminOpHeader, "status")
// Execute GET on bucket to list objects.
resp, err := adm.client.executeMethod("GET", reqData)
resp, err := adm.executeMethod("GET", reqData)
defer closeResponse(resp)
if err != nil {
@ -103,7 +105,7 @@ func (adm *AdminClient) ServiceStop() error {
reqData.customHeaders.Set(minioAdminOpHeader, "stop")
// Execute GET on bucket to list objects.
resp, err := adm.client.executeMethod("POST", reqData)
resp, err := adm.executeMethod("POST", reqData)
defer closeResponse(resp)
if err != nil {
@ -127,7 +129,7 @@ func (adm *AdminClient) ServiceRestart() error {
reqData.customHeaders.Set(minioAdminOpHeader, "restart")
// Execute GET on bucket to list objects.
resp, err := adm.client.executeMethod("POST", reqData)
resp, err := adm.executeMethod("POST", reqData)
defer closeResponse(resp)
if err != nil {