Esempio n. 1
0
func (c *cli) CmdScan(args ...string) error {
	cmd := SubCmd("scan", "[IDENTIFIER]", "(Re-)Scan a mirror")
	enable := cmd.Bool("enable", false, "Enable the mirror automatically if the scan is successful")
	all := cmd.Bool("all", false, "Scan all mirrors at once")
	ftp := cmd.Bool("ftp", false, "Force a scan using FTP")
	rsync := cmd.Bool("rsync", false, "Force a scan using rsync")

	if err := cmd.Parse(args); err != nil {
		return nil
	}
	if !*all && cmd.NArg() != 1 || *all && cmd.NArg() != 0 {
		cmd.Usage()
		return nil
	}

	r := database.NewRedis()
	conn, err := r.Connect()
	if err != nil {
		log.Fatal("Redis: ", err)
	}
	defer conn.Close()

	// Check if the local repository has been scanned already
	exists, err := redis.Bool(conn.Do("EXISTS", "FILES"))
	if err != nil {
		return err
	}
	if !exists {
		fmt.Fprintf(os.Stderr, "Local repository not yet indexed.\nYou should run 'refresh' first!\n")
		os.Exit(-1)
	}

	var list []string

	if *all == true {
		list, err = redis.Strings(conn.Do("LRANGE", "MIRRORS", "0", "-1"))
		if err != nil {
			return errors.New("Cannot fetch the list of mirrors")
		}
	} else {
		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
		}
	}

	for _, id := range list {

		key := fmt.Sprintf("MIRROR_%s", id)
		m, err := redis.Values(conn.Do("HGETALL", key))
		if err != nil {
			fmt.Fprintf(os.Stderr, "Cannot fetch mirror details: %s\n", err)
			return err
		}

		var mirror mirrors.Mirror
		err = redis.ScanStruct(m, &mirror)
		if err != nil {
			return err
		}

		log.Noticef("Scanning %s...", id)

		err = NoSyncMethod

		if *rsync == true || *ftp == true {
			// Use the requested protocol
			if *rsync == true && mirror.RsyncURL != "" {
				err = scan.Scan(scan.RSYNC, r, mirror.RsyncURL, id, nil)
			} else if *ftp == true && mirror.FtpURL != "" {
				err = scan.Scan(scan.FTP, r, mirror.FtpURL, id, nil)
			}
		} else {
			// Use rsync (if applicable) and fallback to FTP
			if mirror.RsyncURL != "" {
				err = scan.Scan(scan.RSYNC, r, mirror.RsyncURL, id, nil)
			}
			if err != nil && mirror.FtpURL != "" {
				err = scan.Scan(scan.FTP, r, mirror.FtpURL, id, nil)
			}
		}

		if err != nil {
			log.Errorf("Scanning %s failed: %s", id, err.Error())
		}

		// Finally enable the mirror if requested
		if err == nil && *enable == true {
			if err := mirrors.EnableMirror(r, id); err != nil {
				log.Fatal("Couldn't enable the mirror: ", err)
			}
			fmt.Println("Mirror enabled successfully")
		}
	}
	return nil
}
Esempio n. 2
0
// Main sync loop
// TODO merge with the monitorLoop?
func (m *Monitor) syncLoop() {
	m.wg.Add(1)
	defer m.wg.Done()
	for {
		select {
		case <-m.stop:
			return
		case k := <-m.syncChan:
			m.mapLock.Lock()
			mirror := m.mirrors[k]
			m.mapLock.Unlock()

			conn := m.redis.Get()
			scanning, err := scan.IsScanning(conn, k)
			if err != nil {
				conn.Close()
				if !database.RedisIsLoading(err) {
					log.Warningf("syncloop: %s", err.Error())
				}
				goto unlock
			} else if scanning {
				// A scan is already in progress on another node
				conn.Close()
				goto unlock
			}
			conn.Close()

			log.Debugf("Scanning %s", k)

			err = cli.NoSyncMethod

			// First try to scan with rsync
			if mirror.RsyncURL != "" {
				err = scan.Scan(scan.RSYNC, m.redis, mirror.RsyncURL, k, m.stop)
			}
			// If it failed or rsync wasn't supported
			// fallback to FTP
			if err != nil && err != scan.ScanAborted && mirror.FtpURL != "" {
				err = scan.Scan(scan.FTP, m.redis, mirror.FtpURL, k, m.stop)
			}

			if err == scan.ScanInProgress {
				log.Warningf("%-30.30s Scan already in progress", k)
				goto unlock
			}

			if mirror.Up == false {
				select {
				case m.healthCheckChan <- k:
				default:
				}
			}

		unlock:
			m.mapLock.Lock()
			if _, ok := m.mirrors[k]; ok {
				m.mirrors[k].scanning = false
			}
			m.mapLock.Unlock()
		}
	}
}