storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/server-startup-msg.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2016, 2017, 2018 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"crypto/x509"
    21  	"fmt"
    22  	"net"
    23  	"runtime"
    24  	"strings"
    25  
    26  	humanize "github.com/dustin/go-humanize"
    27  
    28  	"storj.io/minio/cmd/config"
    29  	"storj.io/minio/cmd/logger"
    30  	color "storj.io/minio/pkg/color"
    31  	"storj.io/minio/pkg/madmin"
    32  	xnet "storj.io/minio/pkg/net"
    33  )
    34  
    35  // Documentation links, these are part of message printing code.
    36  const (
    37  	mcQuickStartGuide     = "https://docs.min.io/docs/minio-client-quickstart-guide"
    38  	goQuickStartGuide     = "https://docs.min.io/docs/golang-client-quickstart-guide"
    39  	jsQuickStartGuide     = "https://docs.min.io/docs/javascript-client-quickstart-guide"
    40  	javaQuickStartGuide   = "https://docs.min.io/docs/java-client-quickstart-guide"
    41  	pyQuickStartGuide     = "https://docs.min.io/docs/python-client-quickstart-guide"
    42  	dotnetQuickStartGuide = "https://docs.min.io/docs/dotnet-client-quickstart-guide"
    43  )
    44  
    45  // generates format string depending on the string length and padding.
    46  func getFormatStr(strLen int, padding int) string {
    47  	formatStr := fmt.Sprintf("%ds", strLen+padding)
    48  	return "%" + formatStr
    49  }
    50  
    51  func mustGetStorageInfo(objAPI ObjectLayer) StorageInfo {
    52  	storageInfo, _ := objAPI.StorageInfo(GlobalContext)
    53  	return storageInfo
    54  }
    55  
    56  // Prints the formatted startup message.
    57  func printStartupMessage(apiEndpoints []string, err error) {
    58  	if err != nil {
    59  		logStartupMessage(color.RedBold("Server startup failed with '%v'", err))
    60  		logStartupMessage(color.RedBold("Not all features may be available on this server"))
    61  		logStartupMessage(color.RedBold("Please use 'mc admin' commands to further investigate this issue"))
    62  	}
    63  
    64  	strippedAPIEndpoints := stripStandardPorts(apiEndpoints)
    65  	// If cache layer is enabled, print cache capacity.
    66  	cachedObjAPI := newCachedObjectLayerFn()
    67  	if cachedObjAPI != nil {
    68  		printCacheStorageInfo(cachedObjAPI.StorageInfo(GlobalContext))
    69  	}
    70  
    71  	// Object layer is initialized then print StorageInfo.
    72  	objAPI := newObjectLayerFn()
    73  	if objAPI != nil {
    74  		printStorageInfo(mustGetStorageInfo(objAPI))
    75  	}
    76  
    77  	// Prints credential, region and browser access.
    78  	printServerCommonMsg(strippedAPIEndpoints)
    79  
    80  	// Prints `mc` cli configuration message chooses
    81  	// first endpoint as default.
    82  	printCLIAccessMsg(strippedAPIEndpoints[0], "myminio")
    83  
    84  	// Prints documentation message.
    85  	printObjectAPIMsg()
    86  
    87  	// SSL is configured reads certification chain, prints
    88  	// authority and expiry.
    89  	if color.IsTerminal() && !GlobalCLIContext.Anonymous {
    90  		if GlobalIsTLS {
    91  			printCertificateMsg(globalPublicCerts)
    92  		}
    93  	}
    94  }
    95  
    96  // Returns true if input is not IPv4, false if it is.
    97  func isNotIPv4(host string) bool {
    98  	h, _, err := net.SplitHostPort(host)
    99  	if err != nil {
   100  		h = host
   101  	}
   102  	ip := net.ParseIP(h)
   103  	ok := ip.To4() != nil // This is always true of IP is IPv4
   104  
   105  	// Returns true if input is not IPv4.
   106  	return !ok
   107  }
   108  
   109  // strip api endpoints list with standard ports such as
   110  // port "80" and "443" before displaying on the startup
   111  // banner.  Returns a new list of API endpoints.
   112  func stripStandardPorts(apiEndpoints []string) (newAPIEndpoints []string) {
   113  	newAPIEndpoints = make([]string, len(apiEndpoints))
   114  	// Check all API endpoints for standard ports and strip them.
   115  	for i, apiEndpoint := range apiEndpoints {
   116  		u, err := xnet.ParseHTTPURL(apiEndpoint)
   117  		if err != nil {
   118  			continue
   119  		}
   120  		if globalMinioHost == "" && isNotIPv4(u.Host) {
   121  			// Skip all non-IPv4 endpoints when we bind to all interfaces.
   122  			continue
   123  		}
   124  		newAPIEndpoints[i] = u.String()
   125  	}
   126  	return newAPIEndpoints
   127  }
   128  
   129  // Prints common server startup message. Prints credential, region and browser access.
   130  func printServerCommonMsg(apiEndpoints []string) {
   131  	// Get saved credentials.
   132  	cred := globalActiveCred
   133  
   134  	// Get saved region.
   135  	region := globalServerRegion
   136  
   137  	apiEndpointStr := strings.Join(apiEndpoints, "  ")
   138  
   139  	// Colorize the message and print.
   140  	logStartupMessage(color.Blue("Endpoint: ") + color.Bold(fmt.Sprintf("%s ", apiEndpointStr)))
   141  	if color.IsTerminal() && !GlobalCLIContext.Anonymous {
   142  		logStartupMessage(color.Blue("RootUser: ") + color.Bold(fmt.Sprintf("%s ", cred.AccessKey)))
   143  		logStartupMessage(color.Blue("RootPass: ") + color.Bold(fmt.Sprintf("%s ", cred.SecretKey)))
   144  		if region != "" {
   145  			logStartupMessage(color.Blue("Region: ") + color.Bold(fmt.Sprintf(getFormatStr(len(region), 2), region)))
   146  		}
   147  	}
   148  	printEventNotifiers()
   149  
   150  	if globalBrowserEnabled {
   151  		logStartupMessage(color.Blue("\nBrowser Access:"))
   152  		logStartupMessage(fmt.Sprintf(getFormatStr(len(apiEndpointStr), 3), apiEndpointStr))
   153  	}
   154  }
   155  
   156  // Prints bucket notification configurations.
   157  func printEventNotifiers() {
   158  	if GlobalNotificationSys == nil {
   159  		return
   160  	}
   161  
   162  	arns := GlobalNotificationSys.GetARNList(true)
   163  	if len(arns) == 0 {
   164  		return
   165  	}
   166  
   167  	arnMsg := color.Blue("SQS ARNs: ")
   168  	for _, arn := range arns {
   169  		arnMsg += color.Bold(fmt.Sprintf("%s ", arn))
   170  	}
   171  
   172  	logStartupMessage(arnMsg)
   173  }
   174  
   175  // Prints startup message for command line access. Prints link to our documentation
   176  // and custom platform specific message.
   177  func printCLIAccessMsg(endPoint string, alias string) {
   178  	// Get saved credentials.
   179  	cred := globalActiveCred
   180  
   181  	// Configure 'mc', following block prints platform specific information for minio client.
   182  	if color.IsTerminal() && !GlobalCLIContext.Anonymous {
   183  		logStartupMessage(color.Blue("\nCommand-line Access: ") + mcQuickStartGuide)
   184  		if runtime.GOOS == globalWindowsOSName {
   185  			mcMessage := fmt.Sprintf("$ mc.exe alias set %s %s %s %s", alias,
   186  				endPoint, cred.AccessKey, cred.SecretKey)
   187  			logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
   188  		} else {
   189  			mcMessage := fmt.Sprintf("$ mc alias set %s %s %s %s", alias,
   190  				endPoint, cred.AccessKey, cred.SecretKey)
   191  			logStartupMessage(fmt.Sprintf(getFormatStr(len(mcMessage), 3), mcMessage))
   192  		}
   193  	}
   194  }
   195  
   196  // Prints startup message for Object API acces, prints link to our SDK documentation.
   197  func printObjectAPIMsg() {
   198  	logStartupMessage(color.Blue("\nObject API (Amazon S3 compatible):"))
   199  	logStartupMessage(color.Blue("   Go: ") + fmt.Sprintf(getFormatStr(len(goQuickStartGuide), 8), goQuickStartGuide))
   200  	logStartupMessage(color.Blue("   Java: ") + fmt.Sprintf(getFormatStr(len(javaQuickStartGuide), 6), javaQuickStartGuide))
   201  	logStartupMessage(color.Blue("   Python: ") + fmt.Sprintf(getFormatStr(len(pyQuickStartGuide), 4), pyQuickStartGuide))
   202  	logStartupMessage(color.Blue("   JavaScript: ") + jsQuickStartGuide)
   203  	logStartupMessage(color.Blue("   .NET: ") + fmt.Sprintf(getFormatStr(len(dotnetQuickStartGuide), 6), dotnetQuickStartGuide))
   204  }
   205  
   206  // Get formatted disk/storage info message.
   207  func getStorageInfoMsg(storageInfo StorageInfo) string {
   208  	var msg string
   209  	var mcMessage string
   210  	onlineDisks, offlineDisks := getOnlineOfflineDisksStats(storageInfo.Disks)
   211  	if storageInfo.Backend.Type == madmin.Erasure {
   212  		if offlineDisks.Sum() > 0 {
   213  			mcMessage = "Use `mc admin info` to look for latest server/disk info\n"
   214  		}
   215  
   216  		diskInfo := fmt.Sprintf(" %d Online, %d Offline. ", onlineDisks.Sum(), offlineDisks.Sum())
   217  		msg += color.Blue("Status:") + fmt.Sprintf(getFormatStr(len(diskInfo), 8), diskInfo)
   218  		if len(mcMessage) > 0 {
   219  			msg = fmt.Sprintf("%s %s", mcMessage, msg)
   220  		}
   221  	}
   222  	return msg
   223  }
   224  
   225  // Prints startup message of storage capacity and erasure information.
   226  func printStorageInfo(storageInfo StorageInfo) {
   227  	if msg := getStorageInfoMsg(storageInfo); msg != "" {
   228  		if GlobalCLIContext.Quiet {
   229  			logger.Info(msg)
   230  		}
   231  		logStartupMessage(msg)
   232  	}
   233  }
   234  
   235  func printCacheStorageInfo(storageInfo CacheStorageInfo) {
   236  	msg := fmt.Sprintf("%s %s Free, %s Total", color.Blue("Cache Capacity:"),
   237  		humanize.IBytes(storageInfo.Free),
   238  		humanize.IBytes(storageInfo.Total))
   239  	logStartupMessage(msg)
   240  }
   241  
   242  // Prints the certificate expiry message.
   243  func printCertificateMsg(certs []*x509.Certificate) {
   244  	for _, cert := range certs {
   245  		logStartupMessage(config.CertificateText(cert))
   246  	}
   247  }