2016-08-30 22:22:27 -04:00
/ *
* 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 cmd
import (
2017-06-17 14:20:12 -04:00
"fmt"
2018-02-15 20:45:57 -05:00
"os"
2016-08-30 22:22:27 -04:00
"time"
2018-02-15 20:45:57 -05:00
"github.com/minio/mc/pkg/console"
2017-11-25 14:58:29 -05:00
"github.com/minio/minio/pkg/errors"
2016-08-30 22:22:27 -04:00
)
2018-02-15 20:45:57 -05:00
var printEndpointError = func ( ) func ( Endpoint , error ) {
printOnce := make ( map [ Endpoint ] map [ string ] bool )
return func ( endpoint Endpoint , err error ) {
m , ok := printOnce [ endpoint ]
if ! ok {
m = make ( map [ string ] bool )
m [ err . Error ( ) ] = true
printOnce [ endpoint ] = m
errorIf ( err , "%s: %s" , endpoint , err )
return
2017-12-28 12:32:48 -05:00
}
2018-02-15 20:45:57 -05:00
if m [ err . Error ( ) ] {
return
2017-12-28 12:32:48 -05:00
}
2018-02-15 20:45:57 -05:00
m [ err . Error ( ) ] = true
errorIf ( err , "%s: %s" , endpoint , err )
2017-12-28 12:32:48 -05:00
}
2018-02-15 20:45:57 -05:00
} ( )
2016-08-30 22:22:27 -04:00
2018-03-15 16:55:23 -04:00
// Migrates backend format of local disks.
2018-02-15 20:45:57 -05:00
func formatXLMigrateLocalEndpoints ( endpoints EndpointList ) error {
for _ , endpoint := range endpoints {
if ! endpoint . IsLocal {
continue
2016-08-30 22:22:27 -04:00
}
2018-02-15 20:45:57 -05:00
formatPath := pathJoin ( endpoint . Path , minioMetaBucket , formatConfigFile )
if _ , err := os . Stat ( formatPath ) ; err != nil {
if os . IsNotExist ( err ) {
continue
}
return err
2016-09-08 12:35:13 -04:00
}
2018-02-15 20:45:57 -05:00
if err := formatXLMigrate ( endpoint . Path ) ; err != nil {
return err
2016-11-23 18:48:10 -05:00
}
}
2018-02-15 20:45:57 -05:00
return nil
2016-11-23 18:48:10 -05:00
}
2018-03-15 16:55:23 -04:00
// Cleans up tmp directory of local disks.
func formatXLCleanupTmpLocalEndpoints ( endpoints EndpointList ) error {
for _ , endpoint := range endpoints {
if ! endpoint . IsLocal {
continue
}
formatPath := pathJoin ( endpoint . Path , minioMetaBucket , formatConfigFile )
if _ , err := os . Stat ( formatPath ) ; err != nil {
if os . IsNotExist ( err ) {
continue
}
return err
}
if err := os . RemoveAll ( pathJoin ( endpoint . Path , minioMetaTmpBucket ) ) ; err != nil {
return err
}
if err := os . MkdirAll ( pathJoin ( endpoint . Path , minioMetaTmpBucket ) , 0777 ) ; err != nil {
return err
}
}
return nil
}
2018-02-15 20:45:57 -05:00
// Format disks before initialization of object layer.
2018-03-15 16:55:23 -04:00
func waitForFormatXL ( firstDisk bool , endpoints EndpointList , setCount , disksPerSet int ) ( format * formatXLV3 , err error ) {
2018-02-15 20:45:57 -05:00
if len ( endpoints ) == 0 || setCount == 0 || disksPerSet == 0 {
return nil , errInvalidArgument
2016-11-02 11:51:06 -04:00
}
2018-02-15 20:45:57 -05:00
if err = formatXLMigrateLocalEndpoints ( endpoints ) ; err != nil {
return nil , err
2016-08-30 22:22:27 -04:00
}
2018-03-15 16:55:23 -04:00
if err = formatXLCleanupTmpLocalEndpoints ( endpoints ) ; err != nil {
return nil , err
}
2017-02-07 05:16:29 -05:00
// Done channel is used to close any lingering retry routine, as soon
// as this function returns.
doneCh := make ( chan struct { } )
2016-08-30 22:22:27 -04:00
2017-02-07 05:16:29 -05:00
// Indicate to our retry routine to exit cleanly, upon this function return.
2016-10-05 15:48:07 -04:00
defer close ( doneCh )
2016-12-07 13:22:00 -05:00
// prepare getElapsedTime() to calculate elapsed time since we started trying formatting disks.
// All times are rounded to avoid showing milli, micro and nano seconds
formatStartTime := time . Now ( ) . Round ( time . Second )
getElapsedTime := func ( ) string {
return time . Now ( ) . Round ( time . Second ) . Sub ( formatStartTime ) . String ( )
}
2016-10-05 15:48:07 -04:00
// Wait on the jitter retry loop.
2017-02-07 05:16:29 -05:00
retryTimerCh := newRetryTimerSimple ( doneCh )
2016-11-02 18:27:36 -04:00
for {
select {
2018-02-15 20:45:57 -05:00
case _ = <- retryTimerCh :
2016-11-23 18:48:10 -05:00
// Attempt to load all `format.json` from all disks.
2018-02-15 20:45:57 -05:00
formatConfigs , sErrs := loadFormatXLAll ( endpoints )
2017-06-17 14:20:12 -04:00
2016-12-11 18:18:55 -05:00
// Pre-emptively check if one of the formatted disks
// is invalid. This function returns success for the
// most part unless one of the formats is not consistent
2017-04-18 13:35:17 -04:00
// with expected XL format. For example if a user is
// trying to pool FS backend into an XL set.
2018-02-15 20:45:57 -05:00
if err = checkFormatXLValues ( formatConfigs ) ; err != nil {
return nil , err
}
for i , sErr := range sErrs {
if _ , ok := formatCriticalErrors [ errors . Cause ( sErr ) ] ; ok {
return nil , fmt . Errorf ( "Disk %s: %s" , endpoints [ i ] , sErr )
}
}
if shouldInitXLDisks ( sErrs ) {
if ! firstDisk {
console . Println ( "Waiting for the first server to format the disks." )
2017-04-18 13:35:17 -04:00
continue
}
2018-02-15 20:45:57 -05:00
return initFormatXL ( endpoints , setCount , disksPerSet )
2016-12-11 18:18:55 -05:00
}
2017-06-17 14:20:12 -04:00
2018-03-19 12:13:00 -04:00
// Following function is added to fix a regressions which was introduced
// in release RELEASE.2018-03-16T22-52-12Z after migrating v1 to v2 to v3.
// This migration failed to capture '.This' field properly which indicates
// the disk UUID association. Below function is called to handle and fix
// this regression, for more info refer https://github.com/minio/minio/issues/5667
if err = fixFormatXLV3 ( endpoints , formatConfigs ) ; err != nil {
return nil , err
}
// If any of the .This field is still empty we wait them to be fixed.
if formatXLV3ThisEmpty ( formatConfigs ) {
continue
}
2018-02-15 20:45:57 -05:00
format , err = getFormatXLInQuorum ( formatConfigs )
if err == nil {
for i := range formatConfigs {
if formatConfigs [ i ] == nil {
continue
}
2018-03-15 16:55:23 -04:00
if err = formatXLV3Check ( format , formatConfigs [ i ] ) ; err != nil {
2018-02-15 20:45:57 -05:00
return nil , fmt . Errorf ( "%s format error: %s" , endpoints [ i ] , err )
}
}
if len ( format . XL . Sets ) != globalXLSetCount {
return nil , fmt . Errorf ( "Current backend format is inconsistent with input args (%s), Expected set count %d, got %d" , endpoints , len ( format . XL . Sets ) , globalXLSetCount )
2016-12-11 18:18:55 -05:00
}
2018-02-15 20:45:57 -05:00
if len ( format . XL . Sets [ 0 ] ) != globalXLSetDriveCount {
return nil , fmt . Errorf ( "Current backend format is inconsistent with input args (%s), Expected drive count per set %d, got %d" , endpoints , len ( format . XL . Sets [ 0 ] ) , globalXLSetDriveCount )
2016-12-11 18:18:55 -05:00
}
2018-02-15 20:45:57 -05:00
return format , nil
2016-12-11 18:18:55 -05:00
}
2018-02-15 20:45:57 -05:00
console . Printf ( "Waiting for a minimum of %d disks to come online (elapsed %s)\n" , len ( endpoints ) / 2 , getElapsedTime ( ) )
2018-02-06 18:07:17 -05:00
case <- globalOSSignalCh :
2018-02-15 20:45:57 -05:00
return nil , fmt . Errorf ( "Initializing data volumes gracefully stopped" )
2016-11-02 18:27:36 -04:00
}
}
2016-08-30 22:22:27 -04:00
}