func (c *cli) CmdDisable(args ...string) error { cmd := SubCmd("disable", "[IDENTIFIER]", "Disable a mirror") if err := cmd.Parse(args); err != nil { return nil } if cmd.NArg() != 1 { cmd.Usage() return nil } // Guess which mirror to use list, err := c.matchMirror(cmd.Arg(0)) if err != nil { return err } if len(list) == 0 { fmt.Fprintf(os.Stderr, "No match for %s\n", cmd.Arg(0)) return nil } else if len(list) > 1 { for _, e := range list { fmt.Fprintf(os.Stderr, "%s\n", e) } return nil } err = mirrors.DisableMirror(database.NewRedis(), list[0]) if err != nil { log.Fatal("Couldn't disable the mirror:", err) } fmt.Println("Mirror disabled successfully") return nil }
func (c *cli) CmdRemove(args ...string) error { cmd := SubCmd("remove", "IDENTIFIER", "Remove an existing mirror") if err := cmd.Parse(args); err != nil { return nil } if cmd.NArg() != 1 { cmd.Usage() return nil } // Guess which mirror to use list, err := c.matchMirror(cmd.Arg(0)) if err != nil { return err } if len(list) == 0 { fmt.Fprintf(os.Stderr, "No match for %s\n", cmd.Arg(0)) return nil } else if len(list) > 1 { for _, e := range list { fmt.Fprintf(os.Stderr, "%s\n", e) } return nil } identifier := list[0] r := database.NewRedis() conn, err := r.Connect() if err != nil { log.Fatal("Redis: ", err) } defer conn.Close() // First disable the mirror mirrors.DisableMirror(r, identifier) // Get all files supported by the given mirror files, err := redis.Strings(conn.Do("SMEMBERS", fmt.Sprintf("MIRROR_%s_FILES", identifier))) if err != nil { log.Fatal("Error: Cannot fetch file list: ", err) } conn.Send("MULTI") // Remove each FILEINFO / FILEMIRRORS for _, file := range files { conn.Send("DEL", fmt.Sprintf("FILEINFO_%s_%s", identifier, file)) conn.Send("SREM", fmt.Sprintf("FILEMIRRORS_%s", file), identifier) conn.Send("PUBLISH", database.MIRROR_FILE_UPDATE, fmt.Sprintf("%s %s", identifier, file)) } _, err = conn.Do("EXEC") if err != nil { log.Fatal("Error: FILEINFO/FILEMIRRORS keys could not be removed: ", err) } // Remove all other keys _, err = conn.Do("DEL", fmt.Sprintf("MIRROR_%s", identifier), fmt.Sprintf("MIRROR_%s_FILES", identifier), fmt.Sprintf("MIRROR_%s_FILES_TMP", identifier), fmt.Sprintf("HANDLEDFILES_%s", identifier), fmt.Sprintf("SCANNING_%s", identifier)) if err != nil { log.Fatal("Error: MIRROR keys could not be removed: ", err) } // Remove the last reference _, err = conn.Do("LREM", "MIRRORS", 0, identifier) if err != nil { log.Fatal("Error: Could not remove the reference from key MIRRORS") } // Publish update database.Publish(conn, database.MIRROR_UPDATE, identifier) fmt.Println("Mirror removed successfully") return nil }
// Do an actual health check against a given mirror func (m *Monitor) healthCheck(mirror mirrors.Mirror) error { // Format log output format := "%-" + fmt.Sprintf("%d.%ds", m.formatLongestID+4, m.formatLongestID+4) // Copy the stop channel to make it nilable locally stopflag := m.stop // Get the URL to a random file available on this mirror file, size, err := m.getRandomFile(mirror.ID) if err != nil { if err == redis.ErrNil { return mirrorNotScanned } else if !database.RedisIsLoading(err) { log.Warningf(format+"Error: Cannot obtain a random file: %s", mirror.ID, err) } return err } // Prepare the HTTP request req, err := http.NewRequest("HEAD", strings.TrimRight(mirror.HttpURL, "/")+file, nil) req.Header.Set("User-Agent", userAgent) req.Close = true done := make(chan bool) var resp *http.Response var elapsed time.Duration // Execute the request inside a goroutine to allow aborting the request go func() { start := time.Now() resp, err = m.httpClient.Do(req) elapsed = time.Since(start) if err == nil { resp.Body.Close() } done <- true }() x: for { select { case <-stopflag: log.Debugf("Aborting health-check for %s", mirror.HttpURL) m.httpTransport.CancelRequest(req) stopflag = nil case <-done: if utils.IsStopped(m.stop) { return nil } break x } } if err != nil { if opErr, ok := err.(*net.OpError); ok { log.Debugf("Op: %s | Net: %s | Addr: %s | Err: %s | Temporary: %t", opErr.Op, opErr.Net, opErr.Addr, opErr.Error(), opErr.Temporary()) } mirrors.MarkMirrorDown(m.redis, mirror.ID, "Unreachable") log.Errorf(format+"Error: %s (%dms)", mirror.ID, err.Error(), elapsed/time.Millisecond) return err } contentLength := resp.Header.Get("Content-Length") if resp.StatusCode == 404 { mirrors.MarkMirrorDown(m.redis, mirror.ID, fmt.Sprintf("File not found %s (error 404)", file)) if GetConfig().DisableOnMissingFile { mirrors.DisableMirror(m.redis, mirror.ID) } log.Errorf(format+"Error: File %s not found (error 404)", mirror.ID, file) } else if resp.StatusCode != 200 { mirrors.MarkMirrorDown(m.redis, mirror.ID, fmt.Sprintf("Got status code %d", resp.StatusCode)) log.Warningf(format+"Down! Status: %d", mirror.ID, resp.StatusCode) } else { mirrors.MarkMirrorUp(m.redis, mirror.ID) rsize, err := strconv.ParseInt(contentLength, 10, 64) if err == nil && rsize != size { log.Warningf(format+"File size mismatch! [%s] (%dms)", mirror.ID, file, elapsed/time.Millisecond) } else { log.Noticef(format+"Up! (%dms)", mirror.ID, elapsed/time.Millisecond) } } return nil }