Example #1
0
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
}
Example #2
0
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
}
Example #3
0
// 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
}