| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | /* | 
					
						
							|  |  |  |  * MinIO Cloud Storage, (C) 2019 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 ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/minio/cmd/logger" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const defaultMonitorNewDiskInterval = time.Minute * 10 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func initLocalDisksAutoHeal() { | 
					
						
							|  |  |  | 	go monitorLocalDisksAndHeal() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // monitorLocalDisksAndHeal - ensures that detected new disks are healed
 | 
					
						
							|  |  |  | //  1. Only the concerned erasure set will be listed and healed
 | 
					
						
							|  |  |  | //  2. Only the node hosting the disk is responsible to perform the heal
 | 
					
						
							|  |  |  | func monitorLocalDisksAndHeal() { | 
					
						
							|  |  |  | 	// Wait until the object layer is ready
 | 
					
						
							|  |  |  | 	var objAPI ObjectLayer | 
					
						
							|  |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2019-11-10 01:27:23 +08:00
										 |  |  | 		objAPI = newObjectLayerWithoutSafeModeFn() | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 		if objAPI == nil { | 
					
						
							|  |  |  | 			time.Sleep(time.Second) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | 	z, ok := objAPI.(*xlZones) | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ctx := context.Background() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var bgSeq *healSequence | 
					
						
							|  |  |  | 	var found bool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		bgSeq, found = globalBackgroundHealState.getHealSequenceByToken(bgHealingUUID) | 
					
						
							|  |  |  | 		if found { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		time.Sleep(time.Second) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 18:35:06 +08:00
										 |  |  | 	// Perform automatic disk healing when a disk is replaced locally.
 | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2020-01-15 17:08:39 +08:00
										 |  |  | 		time.Sleep(defaultMonitorNewDiskInterval) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-10 18:35:06 +08:00
										 |  |  | 		// Attempt a heal as the server starts-up first.
 | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | 		localDisksInZoneHeal := make([]Endpoints, len(z.zones)) | 
					
						
							|  |  |  | 		for i, ep := range globalEndpoints { | 
					
						
							|  |  |  | 			localDisksToHeal := Endpoints{} | 
					
						
							|  |  |  | 			for _, endpoint := range ep.Endpoints { | 
					
						
							|  |  |  | 				if !endpoint.IsLocal { | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// Try to connect to the current endpoint
 | 
					
						
							|  |  |  | 				// and reformat if the current disk is not formatted
 | 
					
						
							|  |  |  | 				_, _, err := connectEndpoint(endpoint) | 
					
						
							|  |  |  | 				if err == errUnformattedDisk { | 
					
						
							|  |  |  | 					localDisksToHeal = append(localDisksToHeal, endpoint) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | 			if len(localDisksToHeal) == 0 { | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | 			localDisksInZoneHeal[i] = localDisksToHeal | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Reformat disks
 | 
					
						
							|  |  |  | 		bgSeq.sourceCh <- SlashSeparator | 
					
						
							| 
									
										
										
										
											2020-01-10 18:35:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 		// Ensure that reformatting disks is finished
 | 
					
						
							|  |  |  | 		bgSeq.sourceCh <- nopHeal | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | 		var erasureSetInZoneToHeal = make([][]int, len(localDisksInZoneHeal)) | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 		// Compute the list of erasure set to heal
 | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | 		for i, localDisksToHeal := range localDisksInZoneHeal { | 
					
						
							|  |  |  | 			var erasureSetToHeal []int | 
					
						
							|  |  |  | 			for _, endpoint := range localDisksToHeal { | 
					
						
							|  |  |  | 				// Load the new format of this passed endpoint
 | 
					
						
							|  |  |  | 				_, format, err := connectEndpoint(endpoint) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					logger.LogIf(ctx, err) | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// Calculate the set index where the current endpoint belongs
 | 
					
						
							|  |  |  | 				setIndex, _, err := findDiskIndex(z.zones[i].format, format) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					logger.LogIf(ctx, err) | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				erasureSetToHeal = append(erasureSetToHeal, setIndex) | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | 			erasureSetInZoneToHeal[i] = erasureSetToHeal | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Heal all erasure sets that need
 | 
					
						
							| 
									
										
										
										
											2019-11-20 09:42:27 +08:00
										 |  |  | 		for i, erasureSetToHeal := range erasureSetInZoneToHeal { | 
					
						
							|  |  |  | 			for _, setIndex := range erasureSetToHeal { | 
					
						
							|  |  |  | 				err := healErasureSet(ctx, setIndex, z.zones[i].sets[setIndex]) | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					logger.LogIf(ctx, err) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-10-29 01:27:49 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |