Remove panic() and handle it appropriately (#5807)

This is an effort to remove panic from the source. 
Add a new call called CriticialIf, that calls LogIf and exits. 
Replace panics with one of CriticalIf, FatalIf and a return of error.
This commit is contained in:
ebozduman 2018-04-19 17:24:43 -07:00 committed by kannappanr
parent 846f3e8f59
commit f16bfda2f2
21 changed files with 129 additions and 128 deletions

View File

@ -220,8 +220,12 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit
return return
} }
host := xnet.MustParseHost(r.RemoteAddr) host, e := xnet.ParseHost(r.RemoteAddr)
target := target.NewHTTPClientTarget(*host, w) logger.CriticalIf(ctx, e)
target, e := target.NewHTTPClientTarget(*host, w)
logger.CriticalIf(ctx, e)
rulesMap := event.NewRulesMap(eventNames, pattern, target.ID()) rulesMap := event.NewRulesMap(eventNames, pattern, target.ID())
if err := globalNotificationSys.AddRemoteTarget(bucketName, target, rulesMap); err != nil { if err := globalNotificationSys.AddRemoteTarget(bucketName, target, rulesMap); err != nil {
@ -233,7 +237,9 @@ func (api objectAPIHandlers) ListenBucketNotificationHandler(w http.ResponseWrit
defer globalNotificationSys.RemoveRemoteTarget(bucketName, target.ID()) defer globalNotificationSys.RemoveRemoteTarget(bucketName, target.ID())
defer globalNotificationSys.RemoveRulesMap(bucketName, rulesMap) defer globalNotificationSys.RemoveRulesMap(bucketName, rulesMap)
thisAddr := xnet.MustParseHost(GetLocalPeer(globalEndpoints)) thisAddr, e := xnet.ParseHost(GetLocalPeer(globalEndpoints))
logger.CriticalIf(ctx, e)
if err := SaveListener(objAPI, bucketName, eventNames, pattern, target.ID(), *thisAddr); err != nil { if err := SaveListener(objAPI, bucketName, eventNames, pattern, target.ID(), *thisAddr); err != nil {
logger.GetReqInfo(ctx).AppendTags("target", target.ID().Name) logger.GetReqInfo(ctx).AppendTags("target", target.ID().Name)
logger.LogIf(ctx, err) logger.LogIf(ctx, err)

View File

@ -22,6 +22,8 @@ import (
"reflect" "reflect"
"sync" "sync"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/auth"
"github.com/minio/minio/pkg/event" "github.com/minio/minio/pkg/event"
"github.com/minio/minio/pkg/event/target" "github.com/minio/minio/pkg/event/target"
@ -167,9 +169,12 @@ func (s *serverConfig) ConfigDiff(t *serverConfig) string {
} }
func newServerConfig() *serverConfig { func newServerConfig() *serverConfig {
cred, err := auth.GetNewCredentials()
logger.FatalIf(err, "")
srvCfg := &serverConfig{ srvCfg := &serverConfig{
Version: serverConfigVersion, Version: serverConfigVersion,
Credential: auth.MustGetNewCredentials(), Credential: cred,
Region: globalMinioDefaultRegion, Region: globalMinioDefaultRegion,
Browser: true, Browser: true,
StorageClass: storageClassConfig{ StorageClass: storageClassConfig{

View File

@ -18,6 +18,7 @@ package cmd
import ( import (
"bytes" "bytes"
"context"
"crypto/hmac" "crypto/hmac"
"crypto/md5" "crypto/md5"
"crypto/rand" "crypto/rand"
@ -27,7 +28,9 @@ import (
"errors" "errors"
"io" "io"
"net/http" "net/http"
"strconv"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/ioutil" "github.com/minio/minio/pkg/ioutil"
sha256 "github.com/minio/sha256-simd" sha256 "github.com/minio/sha256-simd"
"github.com/minio/sio" "github.com/minio/sio"
@ -739,10 +742,9 @@ func (li *ListPartsInfo) IsEncrypted() bool {
// DecryptedSize returns the size of the object after decryption in bytes. // DecryptedSize returns the size of the object after decryption in bytes.
// It returns an error if the object is not encrypted or marked as encrypted // It returns an error if the object is not encrypted or marked as encrypted
// but has an invalid size. // but has an invalid size.
// DecryptedSize panics if the referred object is not encrypted.
func (o *ObjectInfo) DecryptedSize() (int64, error) { func (o *ObjectInfo) DecryptedSize() (int64, error) {
if !o.IsEncrypted() { if !o.IsEncrypted() {
panic("cannot compute decrypted size of an object which is not encrypted") return 0, errors.New("Cannot compute decrypted size of an unencrypted object")
} }
size, err := sio.DecryptedSize(uint64(o.Size)) size, err := sio.DecryptedSize(uint64(o.Size))
if err != nil { if err != nil {
@ -757,7 +759,11 @@ func (o *ObjectInfo) DecryptedSize() (int64, error) {
func (o *ObjectInfo) EncryptedSize() int64 { func (o *ObjectInfo) EncryptedSize() int64 {
size, err := sio.EncryptedSize(uint64(o.Size)) size, err := sio.EncryptedSize(uint64(o.Size))
if err != nil { if err != nil {
panic(err) // Since AWS S3 allows parts to be 5GB at most this cannot happen - sio max. size is 256 TB // This cannot happen since AWS S3 allows parts to be 5GB at most
// sio max. size is 256 TB
reqInfo := (&logger.ReqInfo{}).AppendTags("size", strconv.FormatUint(size, 10))
ctx := logger.SetReqInfo(context.Background(), reqInfo)
logger.CriticalIf(ctx, err)
} }
return int64(size) return int64(size)
} }

View File

@ -344,21 +344,21 @@ func azureToObjectError(err error, params ...string) error {
return err return err
} }
// mustGetAzureUploadID - returns new upload ID which is hex encoded 8 bytes random value. // getAzureUploadID - returns new upload ID which is hex encoded 8 bytes random value.
// this 8 byte restriction is needed because Azure block id has a restriction of length // this 8 byte restriction is needed because Azure block id has a restriction of length
// upto 8 bytes. // upto 8 bytes.
func mustGetAzureUploadID() string { func getAzureUploadID() (string, error) {
var id [8]byte var id [8]byte
n, err := io.ReadFull(rand.Reader, id[:]) n, err := io.ReadFull(rand.Reader, id[:])
if err != nil { if err != nil {
panic(fmt.Errorf("unable to generate upload ID for azure. %s", err)) return "", err
} }
if n != len(id) { if n != len(id) {
panic(fmt.Errorf("insufficient random data (expected: %d, read: %d)", len(id), n)) return "", fmt.Errorf("Unexpected random data size. Expected: %d, read: %d)", len(id), n)
} }
return hex.EncodeToString(id[:]) return hex.EncodeToString(id[:]), nil
} }
// checkAzureUploadID - returns error in case of given string is upload ID. // checkAzureUploadID - returns error in case of given string is upload ID.
@ -724,7 +724,11 @@ func (a *azureObjects) checkUploadIDExists(ctx context.Context, bucketName, obje
// NewMultipartUpload - Use Azure equivalent CreateBlockBlob. // NewMultipartUpload - Use Azure equivalent CreateBlockBlob.
func (a *azureObjects) NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string) (uploadID string, err error) { func (a *azureObjects) NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string) (uploadID string, err error) {
uploadID = mustGetAzureUploadID() uploadID, err = getAzureUploadID()
if err != nil {
logger.LogIf(ctx, err)
return "", err
}
metadataObject := getAzureMetadataObjectName(object, uploadID) metadataObject := getAzureMetadataObjectName(object, uploadID)
var jsonData []byte var jsonData []byte

View File

@ -25,6 +25,7 @@ import (
"time" "time"
humanize "github.com/dustin/go-humanize" humanize "github.com/dustin/go-humanize"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/sys" "github.com/minio/minio/pkg/sys"
"github.com/rs/cors" "github.com/rs/cors"
"golang.org/x/time/rate" "golang.org/x/time/rate"
@ -602,9 +603,7 @@ func (h pathValidityHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// cancelled immediately. // cancelled immediately.
func setRateLimitHandler(h http.Handler) http.Handler { func setRateLimitHandler(h http.Handler) http.Handler {
_, maxLimit, err := sys.GetMaxOpenFileLimit() _, maxLimit, err := sys.GetMaxOpenFileLimit()
if err != nil { logger.CriticalIf(context.Background(), err)
panic(err)
}
// Burst value is set to 1 to allow only maxOpenFileLimit // Burst value is set to 1 to allow only maxOpenFileLimit
// requests to happen at once. // requests to happen at once.
l := rate.NewLimiter(rate.Limit(maxLimit), 1) l := rate.NewLimiter(rate.Limit(maxLimit), 1)

View File

@ -30,7 +30,10 @@ func testAuthenticate(authType string, t *testing.T) {
t.Fatalf("unable initialize config file, %s", err) t.Fatalf("unable initialize config file, %s", err)
} }
defer os.RemoveAll(testPath) defer os.RemoveAll(testPath)
cred := auth.MustGetNewCredentials() cred, err := auth.GetNewCredentials()
if err != nil {
t.Fatalf("Error getting new credentials: %s", err)
}
globalServerConfig.SetCredential(cred) globalServerConfig.SetCredential(cred)
// Define test cases. // Define test cases.

View File

@ -314,7 +314,19 @@ func LogIf(ctx context.Context, err error) {
fmt.Println(output) fmt.Println(output)
} }
// CriticalIf :
// Like LogIf with exit
// It'll be called for fatal error conditions during run-time
func CriticalIf(ctx context.Context, err error) {
if err != nil {
LogIf(ctx, err)
os.Exit(1)
}
}
// FatalIf : // FatalIf :
// Just fatal error message, no stack trace
// It'll be called for input validation failures
func FatalIf(err error, msg string, data ...interface{}) { func FatalIf(err error, msg string, data ...interface{}) {
if err != nil { if err != nil {
if msg != "" { if msg != "" {

View File

@ -181,14 +181,15 @@ func (sys *NotificationSys) initListeners(ctx context.Context, objAPI ObjectLaye
} }
defer objLock.Unlock() defer objLock.Unlock()
reader, err := readConfig(ctx, objAPI, configFile) reader, e := readConfig(ctx, objAPI, configFile)
if err != nil && !IsErrIgnored(err, errDiskNotFound, errNoSuchNotifications) { if e != nil && !IsErrIgnored(e, errDiskNotFound, errNoSuchNotifications) {
return err return e
} }
listenerList := []ListenBucketNotificationArgs{} listenerList := []ListenBucketNotificationArgs{}
if reader != nil { if reader != nil {
if err = json.NewDecoder(reader).Decode(&listenerList); err != nil { err := json.NewDecoder(reader).Decode(&listenerList)
if err != nil {
logger.LogIf(ctx, err) logger.LogIf(ctx, err)
return err return err
} }
@ -201,8 +202,8 @@ func (sys *NotificationSys) initListeners(ctx context.Context, objAPI ObjectLaye
activeListenerList := []ListenBucketNotificationArgs{} activeListenerList := []ListenBucketNotificationArgs{}
for _, args := range listenerList { for _, args := range listenerList {
var found bool found, err := isLocalHost(args.Addr.Name)
if found, err = isLocalHost(args.Addr.Name); err != nil { if err != nil {
logger.GetReqInfo(ctx).AppendTags("host", args.Addr.Name) logger.GetReqInfo(ctx).AppendTags("host", args.Addr.Name)
logger.LogIf(ctx, err) logger.LogIf(ctx, err)
return err return err
@ -217,8 +218,8 @@ func (sys *NotificationSys) initListeners(ctx context.Context, objAPI ObjectLaye
return fmt.Errorf("unable to find PeerRPCClient by address %v in listener.json for bucket %v", args.Addr, bucketName) return fmt.Errorf("unable to find PeerRPCClient by address %v in listener.json for bucket %v", args.Addr, bucketName)
} }
var exist bool exist, err := rpcClient.RemoteTargetExist(bucketName, args.TargetID)
if exist, err = rpcClient.RemoteTargetExist(bucketName, args.TargetID); err != nil { if err != nil {
logger.GetReqInfo(ctx).AppendTags("targetID", args.TargetID.Name) logger.GetReqInfo(ctx).AppendTags("targetID", args.TargetID.Name)
logger.LogIf(ctx, err) logger.LogIf(ctx, err)
return err return err
@ -231,7 +232,7 @@ func (sys *NotificationSys) initListeners(ctx context.Context, objAPI ObjectLaye
target := NewPeerRPCClientTarget(bucketName, args.TargetID, rpcClient) target := NewPeerRPCClientTarget(bucketName, args.TargetID, rpcClient)
rulesMap := event.NewRulesMap(args.EventNames, args.Pattern, target.ID()) rulesMap := event.NewRulesMap(args.EventNames, args.Pattern, target.ID())
if err = sys.AddRemoteTarget(bucketName, target, rulesMap); err != nil { if err = sys.AddRemoteTarget(bucketName, target, rulesMap); err != nil {
logger.GetReqInfo(ctx).AppendTags("targetID", target.id.Name) logger.GetReqInfo(ctx).AppendTags("targetName", target.id.Name)
logger.LogIf(ctx, err) logger.LogIf(ctx, err)
return err return err
} }

View File

@ -168,7 +168,7 @@ func pathJoin(elem ...string) string {
func mustGetUUID() string { func mustGetUUID() string {
uuid, err := uuid.New() uuid, err := uuid.New()
if err != nil { if err != nil {
panic(fmt.Sprintf("Random UUID generation failed. Error: %s", err)) logger.CriticalIf(context.Background(), err)
} }
return uuid.String() return uuid.String()

View File

@ -104,7 +104,7 @@ func (receiver *PeerRPCReceiver) ListenBucketNotification(args *ListenBucketNoti
rulesMap := event.NewRulesMap(args.EventNames, args.Pattern, target.ID()) rulesMap := event.NewRulesMap(args.EventNames, args.Pattern, target.ID())
if err := globalNotificationSys.AddRemoteTarget(args.BucketName, target, rulesMap); err != nil { if err := globalNotificationSys.AddRemoteTarget(args.BucketName, target, rulesMap); err != nil {
reqInfo := &logger.ReqInfo{BucketName: target.bucketName} reqInfo := &logger.ReqInfo{BucketName: target.bucketName}
reqInfo.AppendTags("target", target.id.Name) reqInfo.AppendTags("targetName", target.id.Name)
ctx := logger.SetReqInfo(context.Background(), reqInfo) ctx := logger.SetReqInfo(context.Background(), reqInfo)
logger.LogIf(ctx, err) logger.LogIf(ctx, err)
return err return err
@ -155,14 +155,13 @@ func (receiver *PeerRPCReceiver) SendEvent(args *SendEventArgs, reply *SendEvent
if errMap := globalNotificationSys.send(args.BucketName, args.Event, args.TargetID); len(errMap) != 0 { if errMap := globalNotificationSys.send(args.BucketName, args.Event, args.TargetID); len(errMap) != 0 {
var found bool var found bool
if err, found = errMap[args.TargetID]; !found { if err, found = errMap[args.TargetID]; !found {
// errMap must be zero or one element map because we sent to only one target ID. return fmt.Errorf("error for target %v not found in error map %+v", args.TargetID, errMap)
panic(fmt.Errorf("error for target %v not found in error map %+v", args.TargetID, errMap))
} }
} }
if err != nil { if err != nil {
reqInfo := (&logger.ReqInfo{}).AppendTags("Event", args.Event.EventName.String()) reqInfo := (&logger.ReqInfo{}).AppendTags("Event", args.Event.EventName.String())
reqInfo.AppendTags("target", args.TargetID.Name) reqInfo.AppendTags("targetName", args.TargetID.Name)
ctx := logger.SetReqInfo(context.Background(), reqInfo) ctx := logger.SetReqInfo(context.Background(), reqInfo)
logger.LogIf(ctx, err) logger.LogIf(ctx, err)
} }
@ -275,7 +274,8 @@ func makeRemoteRPCClients(endpoints EndpointList) map[xnet.Host]*PeerRPCClient {
cred := globalServerConfig.GetCredential() cred := globalServerConfig.GetCredential()
serviceEndpoint := path.Join(minioReservedBucketPath, s3Path) serviceEndpoint := path.Join(minioReservedBucketPath, s3Path)
for _, hostStr := range GetRemotePeers(endpoints) { for _, hostStr := range GetRemotePeers(endpoints) {
host := xnet.MustParseHost(hostStr) host, err := xnet.ParseHost(hostStr)
logger.CriticalIf(context.Background(), err)
peerRPCClientMap[*host] = &PeerRPCClient{newAuthRPCClient(authConfig{ peerRPCClientMap[*host] = &PeerRPCClient{newAuthRPCClient(authConfig{
accessKey: cred.AccessKey, accessKey: cred.AccessKey,
secretKey: cred.SecretKey, secretKey: cred.SecretKey,

View File

@ -406,7 +406,8 @@ func (web webAPIHandlers) GenerateAuth(r *http.Request, args *WebGenericArgs, re
if !isHTTPRequestValid(r) { if !isHTTPRequestValid(r) {
return toJSONError(errAuthentication) return toJSONError(errAuthentication)
} }
cred := auth.MustGetNewCredentials() cred, err := auth.GetNewCredentials()
logger.CriticalIf(context.Background(), err)
reply.AccessKey = cred.AccessKey reply.AccessKey = cred.AccessKey
reply.SecretKey = cred.SecretKey reply.SecretKey = cred.SecretKey
reply.UIVersion = browser.UIVersion reply.UIVersion = browser.UIVersion

View File

@ -21,6 +21,7 @@ import (
"crypto" "crypto"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"hash" "hash"
"path" "path"
@ -42,7 +43,7 @@ var DefaultBitrotAlgorithm = HighwayHash256
func init() { func init() {
hh256Key, err := hex.DecodeString(magicHighwayHash256Key) hh256Key, err := hex.DecodeString(magicHighwayHash256Key)
if err != nil || len(hh256Key) != highwayhash.Size { if err != nil || len(hh256Key) != highwayhash.Size {
panic("Failed to decode fixed magic HighwayHash256 key: Please report this bug at https://github.com/minio/minio/issues") logger.CriticalIf(context.Background(), errors.New("Failed to decode fixed magic HighwayHash256 key. Please report this bug at https://github.com/minio/minio/issues"))
} }
newBLAKE2b := func() hash.Hash { newBLAKE2b := func() hash.Hash {
@ -80,11 +81,12 @@ var bitrotAlgorithms = map[BitrotAlgorithm]string{
HighwayHash256: "highwayhash256", HighwayHash256: "highwayhash256",
} }
// New returns a new hash.Hash calculating the given bitrot algorithm. New panics // New returns a new hash.Hash calculating the given bitrot algorithm.
// if the algorithm is not supported or not linked into the binary. // New logs error and exits if the algorithm is not supported or not
// linked into the binary.
func (a BitrotAlgorithm) New() hash.Hash { func (a BitrotAlgorithm) New() hash.Hash {
if _, ok := bitrotAlgorithms[a]; !ok { if _, ok := bitrotAlgorithms[a]; !ok {
panic(fmt.Sprintf("bitrot algorithm #%d is not supported", a)) logger.CriticalIf(context.Background(), errors.New("Unsupported bitrot algorithm"))
} }
return crypto.Hash(a).New() return crypto.Hash(a).New()
} }
@ -98,10 +100,11 @@ func (a BitrotAlgorithm) Available() bool {
// String returns the string identifier for a given bitrot algorithm. // String returns the string identifier for a given bitrot algorithm.
// If the algorithm is not supported String panics. // If the algorithm is not supported String panics.
func (a BitrotAlgorithm) String() string { func (a BitrotAlgorithm) String() string {
if name, ok := bitrotAlgorithms[a]; ok { name, ok := bitrotAlgorithms[a]
return name if !ok {
logger.CriticalIf(context.Background(), errors.New("Unsupported bitrot algorithm"))
} }
panic(fmt.Sprintf("bitrot algorithm #%d is not supported", a)) return name
} }
// BitrotAlgorithmFromString returns a bitrot algorithm from the given string representation. // BitrotAlgorithmFromString returns a bitrot algorithm from the given string representation.

View File

@ -81,30 +81,37 @@ func (cred Credentials) Equal(ccred Credentials) bool {
return cred.AccessKey == ccred.AccessKey && subtle.ConstantTimeCompare([]byte(cred.SecretKey), []byte(ccred.SecretKey)) == 1 return cred.AccessKey == ccred.AccessKey && subtle.ConstantTimeCompare([]byte(cred.SecretKey), []byte(ccred.SecretKey)) == 1
} }
// MustGetNewCredentials generates and returns new credential. // GetNewCredentials generates and returns new credential.
func MustGetNewCredentials() (cred Credentials) { func GetNewCredentials() (cred Credentials, err error) {
readBytes := func(size int) (data []byte) { readBytes := func(size int) (data []byte, err error) {
data = make([]byte, size) data = make([]byte, size)
if n, err := rand.Read(data); err != nil { var n int
panic(err) if n, err = rand.Read(data); err != nil {
return nil, err
} else if n != size { } else if n != size {
panic(fmt.Errorf("not enough data read. expected: %v, got: %v", size, n)) return nil, fmt.Errorf("Not enough data. Expected to read: %v bytes, got: %v bytes", size, n)
} }
return return data, nil
} }
// Generate access key. // Generate access key.
keyBytes := readBytes(accessKeyMaxLen) keyBytes, err := readBytes(accessKeyMaxLen)
if err != nil {
return cred, err
}
for i := 0; i < accessKeyMaxLen; i++ { for i := 0; i < accessKeyMaxLen; i++ {
keyBytes[i] = alphaNumericTable[keyBytes[i]%alphaNumericTableLen] keyBytes[i] = alphaNumericTable[keyBytes[i]%alphaNumericTableLen]
} }
cred.AccessKey = string(keyBytes) cred.AccessKey = string(keyBytes)
// Generate secret key. // Generate secret key.
keyBytes = readBytes(secretKeyMaxLen) keyBytes, err = readBytes(secretKeyMaxLen)
if err != nil {
return cred, err
}
cred.SecretKey = string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen]) cred.SecretKey = string([]byte(base64.StdEncoding.EncodeToString(keyBytes))[:secretKeyMaxLen])
return cred return cred, nil
} }
// CreateCredentials returns new credential with the given access key and secret key. // CreateCredentials returns new credential with the given access key and secret key.

View File

@ -54,8 +54,11 @@ func TestIsSecretKeyValid(t *testing.T) {
} }
} }
func TestMustGetNewCredentials(t *testing.T) { func TestGetNewCredentials(t *testing.T) {
cred := MustGetNewCredentials() cred, err := GetNewCredentials()
if err != nil {
t.Fatalf("Failed to get a new credential")
}
if !cred.IsValid() { if !cred.IsValid() {
t.Fatalf("Failed to get new valid credential") t.Fatalf("Failed to get new valid credential")
} }
@ -106,7 +109,14 @@ func TestCreateCredentials(t *testing.T) {
} }
func TestCredentialsEqual(t *testing.T) { func TestCredentialsEqual(t *testing.T) {
cred := MustGetNewCredentials() cred, err := GetNewCredentials()
if err != nil {
t.Fatalf("Failed to get a new credential")
}
cred2, err := GetNewCredentials()
if err != nil {
t.Fatalf("Failed to get a new credential")
}
testCases := []struct { testCases := []struct {
cred Credentials cred Credentials
ccred Credentials ccred Credentials
@ -119,7 +129,7 @@ func TestCredentialsEqual(t *testing.T) {
// Empty credentials. // Empty credentials.
{Credentials{}, cred, false}, {Credentials{}, cred, false},
// Two different credentialss // Two different credentialss
{cred, MustGetNewCredentials(), false}, {cred, cred2, false},
// Access key is different in credentials to compare. // Access key is different in credentials to compare.
{cred, Credentials{AccessKey: "myuser", SecretKey: cred.SecretKey}, false}, {cred, Credentials{AccessKey: "myuser", SecretKey: cred.SecretKey}, false},
// Secret key is different in credentials to compare. // Secret key is different in credentials to compare.

View File

@ -19,7 +19,6 @@ package target
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"net/http" "net/http"
"sync/atomic" "sync/atomic"
"time" "time"
@ -118,24 +117,28 @@ func (target *HTTPClientTarget) Close() error {
return nil return nil
} }
func mustGetNewUUID() string { func getNewUUID() (string, error) {
uuid, err := uuid.New() uuid, err := uuid.New()
if err != nil { if err != nil {
panic(fmt.Sprintf("%s. Unable to generate random UUID", err)) return "", err
} }
return uuid.String() return uuid.String(), nil
} }
// NewHTTPClientTarget - creates new HTTP client target. // NewHTTPClientTarget - creates new HTTP client target.
func NewHTTPClientTarget(host xnet.Host, w http.ResponseWriter) *HTTPClientTarget { func NewHTTPClientTarget(host xnet.Host, w http.ResponseWriter) (*HTTPClientTarget, error) {
uuid, err := getNewUUID()
if err != nil {
return nil, err
}
c := &HTTPClientTarget{ c := &HTTPClientTarget{
id: event.TargetID{"httpclient" + "+" + mustGetNewUUID() + "+" + host.Name, host.Port.String()}, id: event.TargetID{"httpclient" + "+" + uuid + "+" + host.Name, host.Port.String()},
w: w, w: w,
eventCh: make(chan []byte), eventCh: make(chan []byte),
DoneCh: make(chan struct{}), DoneCh: make(chan struct{}),
stopCh: make(chan struct{}), stopCh: make(chan struct{}),
} }
c.start() c.start()
return c return c, nil
} }

View File

@ -112,7 +112,10 @@ func NewNATSTarget(id string, args NATSArgs) (*NATSTarget, error) {
clientID := args.Streaming.ClientID clientID := args.Streaming.ClientID
if clientID == "" { if clientID == "" {
clientID = mustGetNewUUID() clientID, err = getNewUUID()
if err != nil {
return nil, err
}
} }
connOpts := []stan.Option{stan.NatsURL(addressURL)} connOpts := []stan.Option{stan.NatsURL(addressURL)}

View File

@ -139,12 +139,3 @@ func ParseHost(s string) (*Host, error) {
IsPortSet: isPortSet, IsPortSet: isPortSet,
}, nil }, nil
} }
// MustParseHost - parses given string to Host, else panics.
func MustParseHost(s string) *Host {
host, err := ParseHost(s)
if err != nil {
panic(err)
}
return host
}

View File

@ -207,30 +207,3 @@ func TestParseHost(t *testing.T) {
} }
} }
} }
func TestMustParseHost(t *testing.T) {
testCases := []struct {
s string
expectedHost *Host
}{
{"play", &Host{"play", 0, false}},
{"play:0", &Host{"play", 0, true}},
{"play:9000", &Host{"play", 9000, true}},
{"play.minio.io", &Host{"play.minio.io", 0, false}},
{"play.minio.io:9000", &Host{"play.minio.io", 9000, true}},
{"147.75.201.93", &Host{"147.75.201.93", 0, false}},
{"147.75.201.93:9000", &Host{"147.75.201.93", 9000, true}},
{"play12", &Host{"play12", 0, false}},
{"12play", &Host{"12play", 0, false}},
{"play-minio-io", &Host{"play-minio-io", 0, false}},
{"play--minio.io", &Host{"play--minio.io", 0, false}},
}
for i, testCase := range testCases {
host := MustParseHost(testCase.s)
if !reflect.DeepEqual(host, testCase.expectedHost) {
t.Fatalf("test %v: host: expected: %#v, got: %#v", i+1, testCase.expectedHost, host)
}
}
}

View File

@ -42,13 +42,3 @@ func ParsePort(s string) (p Port, err error) {
return Port(i), nil return Port(i), nil
} }
// MustParsePort - parses string into Port, else panics
func MustParsePort(s string) Port {
p, err := ParsePort(s)
if err != nil {
panic(err)
}
return p
}

View File

@ -71,22 +71,3 @@ func TestParsePort(t *testing.T) {
} }
} }
} }
func TestMustParsePort(t *testing.T) {
testCases := []struct {
s string
expectedPort Port
}{
{"0", Port(0)},
{"9000", Port(9000)},
{"65535", Port(65535)},
}
for i, testCase := range testCases {
port := MustParsePort(testCase.s)
if port != testCase.expectedPort {
t.Fatalf("test %v: error: port: %v, got: %v", i+1, testCase.expectedPort, port)
}
}
}

View File

@ -35,7 +35,10 @@ func (u URL) IsEmpty() bool {
func (u URL) String() string { func (u URL) String() string {
// if port number 80 and 443, remove for http and https scheme respectively // if port number 80 and 443, remove for http and https scheme respectively
if u.Host != "" { if u.Host != "" {
host := MustParseHost(u.Host) host, err := ParseHost(u.Host)
if err != nil {
panic(err)
}
switch { switch {
case u.Scheme == "http" && host.Port == 80: case u.Scheme == "http" && host.Port == 80:
fallthrough fallthrough