update snapshot processing
This commit is contained in:
		
							parent
							
								
									e192906265
								
							
						
					
					
						commit
						0d3981ef4a
					
				
							
								
								
									
										202
									
								
								app.go
									
									
									
									
									
								
							
							
						
						
									
										202
									
								
								app.go
									
									
									
									
									
								
							@ -16,8 +16,7 @@ type AppConfig struct {
 | 
				
			|||||||
	After        map[string]Location `json:"after"`
 | 
						After        map[string]Location `json:"after"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) getSchedule() (string, error) {
 | 
					func (a AppConfig) getSchedule() (schedule string, err error) {
 | 
				
			||||||
	var schedule string
 | 
					 | 
				
			||||||
	if *debugFlag {
 | 
						if *debugFlag {
 | 
				
			||||||
		log.Printf("AppConfig.getSchedule : %s : Start", a.Name)
 | 
							log.Printf("AppConfig.getSchedule : %s : Start", a.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -36,38 +35,42 @@ func (a AppConfig) getSchedule() (string, error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var ok bool
 | 
				
			||||||
	if *schedFlag != "" {
 | 
						if *schedFlag != "" {
 | 
				
			||||||
		schedule = *schedFlag
 | 
							schedule = *schedFlag
 | 
				
			||||||
	} else if a.needYearlySnapshot() {
 | 
						} else if ok, err = a.needYearlySnapshot(); ok && err == nil {
 | 
				
			||||||
		schedule = "yearly"
 | 
							schedule = "yearly"
 | 
				
			||||||
	} else if a.needMonthlySnapshot() {
 | 
						} else if ok, err = a.needMonthlySnapshot(); ok && err == nil {
 | 
				
			||||||
		schedule = "monthly"
 | 
							schedule = "monthly"
 | 
				
			||||||
	} else if a.needWeeklySnapshot() {
 | 
						} else if ok, err = a.needWeeklySnapshot(); ok && err == nil {
 | 
				
			||||||
		schedule = "weekly"
 | 
							schedule = "weekly"
 | 
				
			||||||
	} else if a.needDailySnapshot() {
 | 
						} else if ok, err = a.needDailySnapshot(); ok && err == nil {
 | 
				
			||||||
		schedule = "daily"
 | 
							schedule = "daily"
 | 
				
			||||||
	} else if a.needHourlySnapshot() {
 | 
						} else if ok, err = a.needHourlySnapshot(); ok && err == nil {
 | 
				
			||||||
		schedule = "hourly"
 | 
							schedule = "hourly"
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return schedule, nil
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ret, ok := cfg.Zfsnap[schedule]; !ok {
 | 
						if ret, ok := cfg.Zfsnap[schedule]; !ok {
 | 
				
			||||||
		return "", fmt.Errorf("no retention for %s", schedule)
 | 
							schedule = ""
 | 
				
			||||||
 | 
							err = fmt.Errorf("no retention for %s", schedule)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		re := regexp.MustCompile(`^([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
							re := regexp.MustCompile(`^([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
				
			||||||
		if !re.MatchString(ret) {
 | 
							if !re.MatchString(ret) {
 | 
				
			||||||
			return "", fmt.Errorf("wrong retention format for %s", schedule)
 | 
								schedule = ""
 | 
				
			||||||
 | 
								err = fmt.Errorf("wrong retention format for %s", schedule)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return schedule, nil
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) needYearlySnapshot() bool {
 | 
					func (a AppConfig) needYearlySnapshot() (ret bool, err error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if *debugFlag {
 | 
						if *debugFlag {
 | 
				
			||||||
		log.Printf("AppConfig.needYearlySnapshot : %s : Start", a.Name)
 | 
							log.Printf("AppConfig.needYearlySnapshot : %s : Start", a.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ret := false
 | 
						ret = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// schedule enabled for app ?
 | 
						// schedule enabled for app ?
 | 
				
			||||||
	for _, v := range a.Schedule {
 | 
						for _, v := range a.Schedule {
 | 
				
			||||||
@ -76,7 +79,7 @@ func (a AppConfig) needYearlySnapshot() bool {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !ret {
 | 
						if !ret {
 | 
				
			||||||
		return false
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// finding out the timestamps existing
 | 
						// finding out the timestamps existing
 | 
				
			||||||
@ -85,15 +88,25 @@ func (a AppConfig) needYearlySnapshot() bool {
 | 
				
			|||||||
	re := regexp.MustCompile(`^yearly-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
						re := regexp.MustCompile(`^yearly-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
				
			||||||
	for _, src := range a.Sources {
 | 
						for _, src := range a.Sources {
 | 
				
			||||||
		timeSource[string(src)] = make(map[time.Time]struct{})
 | 
							timeSource[string(src)] = make(map[time.Time]struct{})
 | 
				
			||||||
		for _, snap := range cfg.Box[src.Box()].ZFSGetSnapshotList() {
 | 
					
 | 
				
			||||||
 | 
							var snapList []Snapshot
 | 
				
			||||||
 | 
							snapList, err = cfg.Box[src.Box()].ZFSGetSnapshotList()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, snap := range snapList {
 | 
				
			||||||
			if src.Path() == snap.Path() {
 | 
								if src.Path() == snap.Path() {
 | 
				
			||||||
				if re.MatchString(snap.Name()) {
 | 
									if re.MatchString(snap.Name()) {
 | 
				
			||||||
					dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
										dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
				
			||||||
					dateTime, err := time.Parse("2006-01-02_15.04.05", dateString)
 | 
					
 | 
				
			||||||
 | 
										var dateTime time.Time
 | 
				
			||||||
 | 
										dateTime, err = time.ParseInLocation("2006-01-02_15.04.05", dateString, time.Now().Location())
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						if *debugFlag {
 | 
											if *debugFlag {
 | 
				
			||||||
							log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
												log.Printf("AppConfig.needYearlySnapshot : %s : time.ParseInLocation(%s) : %s", a.Name, dateString, err)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						timeSource[string(src)][dateTime] = struct{}{}
 | 
											timeSource[string(src)][dateTime] = struct{}{}
 | 
				
			||||||
						timeTotal[dateTime] = struct{}{}
 | 
											timeTotal[dateTime] = struct{}{}
 | 
				
			||||||
@ -115,20 +128,20 @@ func (a AppConfig) needYearlySnapshot() bool {
 | 
				
			|||||||
	// finding an eligible timestamp
 | 
						// finding an eligible timestamp
 | 
				
			||||||
	for t, _ := range timeTotal {
 | 
						for t, _ := range timeTotal {
 | 
				
			||||||
		if t.Year() == cfg.Now.Year() {
 | 
							if t.Year() == cfg.Now.Year() {
 | 
				
			||||||
			return false
 | 
								ret = false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// no timestamp => need the snapshot !
 | 
						// no timestamp => need the snapshot !
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) needMonthlySnapshot() bool {
 | 
					func (a AppConfig) needMonthlySnapshot() (ret bool, err error) {
 | 
				
			||||||
	if *debugFlag {
 | 
						if *debugFlag {
 | 
				
			||||||
		log.Printf("AppConfig.needMonthlySnapshot : %s : Start", a.Name)
 | 
							log.Printf("AppConfig.needMonthlySnapshot : %s : Start", a.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ret := false
 | 
						ret = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// schedule enabled for app ?
 | 
						// schedule enabled for app ?
 | 
				
			||||||
	for _, v := range a.Schedule {
 | 
						for _, v := range a.Schedule {
 | 
				
			||||||
@ -137,7 +150,7 @@ func (a AppConfig) needMonthlySnapshot() bool {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !ret {
 | 
						if !ret {
 | 
				
			||||||
		return false
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// finding out the timestamps existing
 | 
						// finding out the timestamps existing
 | 
				
			||||||
@ -146,15 +159,25 @@ func (a AppConfig) needMonthlySnapshot() bool {
 | 
				
			|||||||
	re := regexp.MustCompile(`^(yearly|monthly)-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
						re := regexp.MustCompile(`^(yearly|monthly)-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
				
			||||||
	for _, src := range a.Sources {
 | 
						for _, src := range a.Sources {
 | 
				
			||||||
		timeSource[string(src)] = make(map[time.Time]struct{})
 | 
							timeSource[string(src)] = make(map[time.Time]struct{})
 | 
				
			||||||
		for _, snap := range cfg.Box[src.Box()].ZFSGetSnapshotList() {
 | 
					
 | 
				
			||||||
 | 
							var snapList []Snapshot
 | 
				
			||||||
 | 
							snapList, err = cfg.Box[src.Box()].ZFSGetSnapshotList()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, snap := range snapList {
 | 
				
			||||||
			if src.Path() == snap.Path() {
 | 
								if src.Path() == snap.Path() {
 | 
				
			||||||
				if re.MatchString(snap.Name()) {
 | 
									if re.MatchString(snap.Name()) {
 | 
				
			||||||
					dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
										dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
				
			||||||
					dateTime, err := time.Parse("2006-01-02_15.04.05", dateString)
 | 
					
 | 
				
			||||||
 | 
										var dateTime time.Time
 | 
				
			||||||
 | 
										dateTime, err = time.ParseInLocation("2006-01-02_15.04.05", dateString, time.Now().Location())
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						if *debugFlag {
 | 
											if *debugFlag {
 | 
				
			||||||
							log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
												log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						timeSource[string(src)][dateTime] = struct{}{}
 | 
											timeSource[string(src)][dateTime] = struct{}{}
 | 
				
			||||||
						timeTotal[dateTime] = struct{}{}
 | 
											timeTotal[dateTime] = struct{}{}
 | 
				
			||||||
@ -176,20 +199,20 @@ func (a AppConfig) needMonthlySnapshot() bool {
 | 
				
			|||||||
	// finding an eligible timestamp
 | 
						// finding an eligible timestamp
 | 
				
			||||||
	for t, _ := range timeTotal {
 | 
						for t, _ := range timeTotal {
 | 
				
			||||||
		if t.Year() == cfg.Now.Year() && t.Month() == cfg.Now.Month() {
 | 
							if t.Year() == cfg.Now.Year() && t.Month() == cfg.Now.Month() {
 | 
				
			||||||
			return false
 | 
								ret = false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// no timestamp => need the snapshot !
 | 
						// no timestamp => need the snapshot !
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) needWeeklySnapshot() bool {
 | 
					func (a AppConfig) needWeeklySnapshot() (ret bool, err error) {
 | 
				
			||||||
	if *debugFlag {
 | 
						if *debugFlag {
 | 
				
			||||||
		log.Printf("AppConfig.needWeeklySnapshot : %s : Start", a.Name)
 | 
							log.Printf("AppConfig.needWeeklySnapshot : %s : Start", a.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ret := false
 | 
						ret = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// schedule enabled for app ?
 | 
						// schedule enabled for app ?
 | 
				
			||||||
	for _, v := range a.Schedule {
 | 
						for _, v := range a.Schedule {
 | 
				
			||||||
@ -198,7 +221,7 @@ func (a AppConfig) needWeeklySnapshot() bool {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !ret {
 | 
						if !ret {
 | 
				
			||||||
		return false
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// finding out the timestamps existing
 | 
						// finding out the timestamps existing
 | 
				
			||||||
@ -207,15 +230,25 @@ func (a AppConfig) needWeeklySnapshot() bool {
 | 
				
			|||||||
	re := regexp.MustCompile(`^(yearly|monthly|weekly)-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
						re := regexp.MustCompile(`^(yearly|monthly|weekly)-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
				
			||||||
	for _, src := range a.Sources {
 | 
						for _, src := range a.Sources {
 | 
				
			||||||
		timeSource[string(src)] = make(map[time.Time]struct{})
 | 
							timeSource[string(src)] = make(map[time.Time]struct{})
 | 
				
			||||||
		for _, snap := range cfg.Box[src.Box()].ZFSGetSnapshotList() {
 | 
					
 | 
				
			||||||
 | 
							var snapList []Snapshot
 | 
				
			||||||
 | 
							snapList, err = cfg.Box[src.Box()].ZFSGetSnapshotList()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, snap := range snapList {
 | 
				
			||||||
			if src.Path() == snap.Path() {
 | 
								if src.Path() == snap.Path() {
 | 
				
			||||||
				if re.MatchString(snap.Name()) {
 | 
									if re.MatchString(snap.Name()) {
 | 
				
			||||||
					dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
										dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
				
			||||||
					dateTime, err := time.Parse("2006-01-02_15.04.05", dateString)
 | 
					
 | 
				
			||||||
 | 
										var dateTime time.Time
 | 
				
			||||||
 | 
										dateTime, err = time.ParseInLocation("2006-01-02_15.04.05", dateString, time.Now().Location())
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						if *debugFlag {
 | 
											if *debugFlag {
 | 
				
			||||||
							log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
												log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						timeSource[string(src)][dateTime] = struct{}{}
 | 
											timeSource[string(src)][dateTime] = struct{}{}
 | 
				
			||||||
						timeTotal[dateTime] = struct{}{}
 | 
											timeTotal[dateTime] = struct{}{}
 | 
				
			||||||
@ -239,20 +272,20 @@ func (a AppConfig) needWeeklySnapshot() bool {
 | 
				
			|||||||
	for t, _ := range timeTotal {
 | 
						for t, _ := range timeTotal {
 | 
				
			||||||
		snapYear, snapWeek := t.ISOWeek()
 | 
							snapYear, snapWeek := t.ISOWeek()
 | 
				
			||||||
		if nowYear == snapYear && nowWeek == snapWeek {
 | 
							if nowYear == snapYear && nowWeek == snapWeek {
 | 
				
			||||||
			return false
 | 
								ret = false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// no timestamp => need the snapshot !
 | 
						// no timestamp => need the snapshot !
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) needDailySnapshot() bool {
 | 
					func (a AppConfig) needDailySnapshot() (ret bool, err error) {
 | 
				
			||||||
	if *debugFlag {
 | 
						if *debugFlag {
 | 
				
			||||||
		log.Printf("AppConfig.needDailySnapshot : %s : Start", a.Name)
 | 
							log.Printf("AppConfig.needDailySnapshot : %s : Start", a.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ret := false
 | 
						ret = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// schedule enabled for app ?
 | 
						// schedule enabled for app ?
 | 
				
			||||||
	for _, v := range a.Schedule {
 | 
						for _, v := range a.Schedule {
 | 
				
			||||||
@ -261,7 +294,7 @@ func (a AppConfig) needDailySnapshot() bool {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !ret {
 | 
						if !ret {
 | 
				
			||||||
		return false
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// finding out the timestamps existing
 | 
						// finding out the timestamps existing
 | 
				
			||||||
@ -270,15 +303,25 @@ func (a AppConfig) needDailySnapshot() bool {
 | 
				
			|||||||
	re := regexp.MustCompile(`^(yearly|monthly|weekly|daily)-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
						re := regexp.MustCompile(`^(yearly|monthly|weekly|daily)-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
				
			||||||
	for _, src := range a.Sources {
 | 
						for _, src := range a.Sources {
 | 
				
			||||||
		timeSource[string(src)] = make(map[time.Time]struct{})
 | 
							timeSource[string(src)] = make(map[time.Time]struct{})
 | 
				
			||||||
		for _, snap := range cfg.Box[src.Box()].ZFSGetSnapshotList() {
 | 
					
 | 
				
			||||||
 | 
							var snapList []Snapshot
 | 
				
			||||||
 | 
							snapList, err = cfg.Box[src.Box()].ZFSGetSnapshotList()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, snap := range snapList {
 | 
				
			||||||
			if src.Path() == snap.Path() {
 | 
								if src.Path() == snap.Path() {
 | 
				
			||||||
				if re.MatchString(snap.Name()) {
 | 
									if re.MatchString(snap.Name()) {
 | 
				
			||||||
					dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
										dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
				
			||||||
					dateTime, err := time.Parse("2006-01-02_15.04.05", dateString)
 | 
					
 | 
				
			||||||
 | 
										var dateTime time.Time
 | 
				
			||||||
 | 
										dateTime, err = time.ParseInLocation("2006-01-02_15.04.05", dateString, time.Now().Location())
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						if *debugFlag {
 | 
											if *debugFlag {
 | 
				
			||||||
							log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
												log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						timeSource[string(src)][dateTime] = struct{}{}
 | 
											timeSource[string(src)][dateTime] = struct{}{}
 | 
				
			||||||
						timeTotal[dateTime] = struct{}{}
 | 
											timeTotal[dateTime] = struct{}{}
 | 
				
			||||||
@ -300,20 +343,20 @@ func (a AppConfig) needDailySnapshot() bool {
 | 
				
			|||||||
	// finding an eligible timestamp
 | 
						// finding an eligible timestamp
 | 
				
			||||||
	for t, _ := range timeTotal {
 | 
						for t, _ := range timeTotal {
 | 
				
			||||||
		if t.Year() == cfg.Now.Year() && t.Month() == cfg.Now.Month() && t.Day() == cfg.Now.Day() {
 | 
							if t.Year() == cfg.Now.Year() && t.Month() == cfg.Now.Month() && t.Day() == cfg.Now.Day() {
 | 
				
			||||||
			return false
 | 
								ret = false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// no timestamp => need the snapshot !
 | 
						// no timestamp => need the snapshot !
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) needHourlySnapshot() bool {
 | 
					func (a AppConfig) needHourlySnapshot() (ret bool, err error) {
 | 
				
			||||||
	if *debugFlag {
 | 
						if *debugFlag {
 | 
				
			||||||
		log.Printf("AppConfig.needHourlySnapshot : %s : Start", a.Name)
 | 
							log.Printf("AppConfig.needHourlySnapshot : %s : Start", a.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ret := false
 | 
						ret = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// schedule enabled for app ?
 | 
						// schedule enabled for app ?
 | 
				
			||||||
	for _, v := range a.Schedule {
 | 
						for _, v := range a.Schedule {
 | 
				
			||||||
@ -322,7 +365,7 @@ func (a AppConfig) needHourlySnapshot() bool {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !ret {
 | 
						if !ret {
 | 
				
			||||||
		return false
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// finding out the timestamps existing
 | 
						// finding out the timestamps existing
 | 
				
			||||||
@ -331,15 +374,25 @@ func (a AppConfig) needHourlySnapshot() bool {
 | 
				
			|||||||
	re := regexp.MustCompile(`^(yearly|monthly|weekly|daily|hourly)-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
						re := regexp.MustCompile(`^(yearly|monthly|weekly|daily|hourly)-(?P<Date>[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}.[0-9]{2}.[0-9]{2})--([0-9]+[ymwdhMs]{1}|forever)$`)
 | 
				
			||||||
	for _, src := range a.Sources {
 | 
						for _, src := range a.Sources {
 | 
				
			||||||
		timeSource[string(src)] = make(map[time.Time]struct{})
 | 
							timeSource[string(src)] = make(map[time.Time]struct{})
 | 
				
			||||||
		for _, snap := range cfg.Box[src.Box()].ZFSGetSnapshotList() {
 | 
					
 | 
				
			||||||
 | 
							var snapList []Snapshot
 | 
				
			||||||
 | 
							snapList, err = cfg.Box[src.Box()].ZFSGetSnapshotList()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, snap := range snapList {
 | 
				
			||||||
			if src.Path() == snap.Path() {
 | 
								if src.Path() == snap.Path() {
 | 
				
			||||||
				if re.MatchString(snap.Name()) {
 | 
									if re.MatchString(snap.Name()) {
 | 
				
			||||||
					dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
										dateString := re.ReplaceAllString(snap.Name(), "${Date}")
 | 
				
			||||||
					dateTime, err := time.Parse("2006-01-02_15.04.05", dateString)
 | 
					
 | 
				
			||||||
 | 
										var dateTime time.Time
 | 
				
			||||||
 | 
										dateTime, err = time.ParseInLocation("2006-01-02_15.04.05", dateString, time.Now().Location())
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						if *debugFlag {
 | 
											if *debugFlag {
 | 
				
			||||||
							log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
												log.Printf("AppConfig.needYearlySnapshot : %s : time.Parse(%s) : %s", a.Name, dateString, err)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						timeSource[string(src)][dateTime] = struct{}{}
 | 
											timeSource[string(src)][dateTime] = struct{}{}
 | 
				
			||||||
						timeTotal[dateTime] = struct{}{}
 | 
											timeTotal[dateTime] = struct{}{}
 | 
				
			||||||
@ -361,13 +414,13 @@ func (a AppConfig) needHourlySnapshot() bool {
 | 
				
			|||||||
	// finding an eligible timestamp
 | 
						// finding an eligible timestamp
 | 
				
			||||||
	for t, _ := range timeTotal {
 | 
						for t, _ := range timeTotal {
 | 
				
			||||||
		if t.Year() == cfg.Now.Year() && t.Month() == cfg.Now.Month() && t.Day() == cfg.Now.Day() && t.Hour() == cfg.Now.Hour() {
 | 
							if t.Year() == cfg.Now.Year() && t.Month() == cfg.Now.Month() && t.Day() == cfg.Now.Day() && t.Hour() == cfg.Now.Hour() {
 | 
				
			||||||
			return false
 | 
								ret = false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// no timestamp => need the snapshot !
 | 
						// no timestamp => need the snapshot !
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) CheckZFS() error {
 | 
					func (a AppConfig) CheckZFS() error {
 | 
				
			||||||
@ -480,7 +533,7 @@ func (a AppConfig) RefreshSnapshot() error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) SendSnapshots() error {
 | 
					func (a AppConfig) SendSnapshots() (err error) {
 | 
				
			||||||
	if *debugFlag {
 | 
						if *debugFlag {
 | 
				
			||||||
		log.Printf("AppConfig.SendSnapshots : %s : Start", a.Name)
 | 
							log.Printf("AppConfig.SendSnapshots : %s : Start", a.Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -490,18 +543,23 @@ func (a AppConfig) SendSnapshots() error {
 | 
				
			|||||||
			if *debugFlag {
 | 
								if *debugFlag {
 | 
				
			||||||
				log.Printf("AppConfig.SendSnapshots : %s : Sending snapshots from %s to %s", a.Name, string(src), string(dest))
 | 
									log.Printf("AppConfig.SendSnapshots : %s : Sending snapshots from %s to %s", a.Name, string(src), string(dest))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			dLastSnapshot, err := cfg.Box[dest.Box()].ZFSGetLastSnapshot(dest.Path() + "/" + src.Box() + "/" + src.Path())
 | 
					
 | 
				
			||||||
			if err != nil {
 | 
								var dLastSnapshot Snapshot
 | 
				
			||||||
 | 
								dLastSnapshot, err = cfg.Box[dest.Box()].ZFSGetLastSnapshot(dest.Path() + "/" + src.Box() + "/" + src.Path())
 | 
				
			||||||
 | 
								if err != nil && err.Error() == "no snapshot" {
 | 
				
			||||||
				if *debugFlag {
 | 
									if *debugFlag {
 | 
				
			||||||
					log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s on %s", a.Name, string(src), dest.Box())
 | 
										log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s on %s", a.Name, string(src), dest.Box())
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				sFirstSnapshot, err := cfg.Box[src.Box()].ZFSGetFirstSnapshot(src.Path())
 | 
					
 | 
				
			||||||
 | 
									var sFirstSnapshot Snapshot
 | 
				
			||||||
 | 
									sFirstSnapshot, err = cfg.Box[src.Box()].ZFSGetFirstSnapshot(src.Path())
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					if *debugFlag {
 | 
										if *debugFlag {
 | 
				
			||||||
						log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s", a.Name, string(src))
 | 
											log.Printf("AppConfig.SendSnapshots : %s : No snapshot for %s", a.Name, string(src))
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					return err
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if *debugFlag {
 | 
									if *debugFlag {
 | 
				
			||||||
					log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s", a.Name, dest.Box(), string(sFirstSnapshot))
 | 
										log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s", a.Name, dest.Box(), string(sFirstSnapshot))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@ -510,23 +568,32 @@ func (a AppConfig) SendSnapshots() error {
 | 
				
			|||||||
					if *debugFlag {
 | 
										if *debugFlag {
 | 
				
			||||||
						log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sFirstSnapshot), err)
 | 
											log.Printf("AppConfig.SendSnapshots : %s : Initializing snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sFirstSnapshot), err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					return err
 | 
										return
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				var sCurrSnapshot Snapshot
 | 
					
 | 
				
			||||||
				sNextSnapshot := sFirstSnapshot
 | 
									var (
 | 
				
			||||||
				for !cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) {
 | 
										sCurrSnapshot, sNextSnapshot Snapshot
 | 
				
			||||||
 | 
										isLastSnapshot               bool
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
 | 
									sNextSnapshot = sFirstSnapshot
 | 
				
			||||||
 | 
									isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot)
 | 
				
			||||||
 | 
									for !isLastSnapshot {
 | 
				
			||||||
					sCurrSnapshot = sNextSnapshot
 | 
										sCurrSnapshot = sNextSnapshot
 | 
				
			||||||
					sNextSnapshot, err = cfg.Box[src.Box()].ZFSGetNextSnapshot(sNextSnapshot)
 | 
										sNextSnapshot, err = cfg.Box[src.Box()].ZFSGetNextSnapshot(sNextSnapshot)
 | 
				
			||||||
					if *debugFlag {
 | 
										if *debugFlag {
 | 
				
			||||||
						log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box())
 | 
											log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box())
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										if err != nil && err.Error() != "no snapshot" {
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
					_, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path())
 | 
										_, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path())
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						if *debugFlag {
 | 
											if *debugFlag {
 | 
				
			||||||
							log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err)
 | 
												log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						return err
 | 
											return
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if *debugFlag {
 | 
									if *debugFlag {
 | 
				
			||||||
					log.Printf("AppConfig.SendSnapshots : %s : All snapshots sent for %s", a.Name, string(src))
 | 
										log.Printf("AppConfig.SendSnapshots : %s : All snapshots sent for %s", a.Name, string(src))
 | 
				
			||||||
@ -536,26 +603,35 @@ func (a AppConfig) SendSnapshots() error {
 | 
				
			|||||||
				if *debugFlag {
 | 
									if *debugFlag {
 | 
				
			||||||
					log.Printf("AppConfig.SendSnapshots : %s : Last snapshot on %s is %s", a.Name, dest.Box(), string(dLastSnapshot))
 | 
										log.Printf("AppConfig.SendSnapshots : %s : Last snapshot on %s is %s", a.Name, dest.Box(), string(dLastSnapshot))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				var sCurrSnapshot Snapshot
 | 
									var (
 | 
				
			||||||
				sNextSnapshot := Snapshot(string(dLastSnapshot)[len(dest.Path())+len(src.Box())+2:])
 | 
										sCurrSnapshot, sNextSnapshot Snapshot
 | 
				
			||||||
				for !cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot) {
 | 
										isLastSnapshot               bool
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
 | 
									sNextSnapshot = Snapshot(string(dLastSnapshot)[len(dest.Path())+len(src.Box())+2:])
 | 
				
			||||||
 | 
									isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot)
 | 
				
			||||||
 | 
									for !isLastSnapshot {
 | 
				
			||||||
					sCurrSnapshot = sNextSnapshot
 | 
										sCurrSnapshot = sNextSnapshot
 | 
				
			||||||
					sNextSnapshot, err = cfg.Box[src.Box()].ZFSGetNextSnapshot(sNextSnapshot)
 | 
										sNextSnapshot, err = cfg.Box[src.Box()].ZFSGetNextSnapshot(sNextSnapshot)
 | 
				
			||||||
					if *debugFlag {
 | 
										if *debugFlag {
 | 
				
			||||||
						log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box())
 | 
											log.Printf("AppConfig.SendSnapshots : %s : Sending incrementally %s to %s", a.Name, string(sNextSnapshot), dest.Box())
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										if err != nil && err.Error() != "no snapshot" {
 | 
				
			||||||
 | 
											return
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
					_, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path())
 | 
										_, err = cfg.Box[dest.Box()].SSHExec("ssh " + cfg.Box[src.Box()].User + "@" + src.Box() + " zfs send -I " + string(sCurrSnapshot) + " " + string(sNextSnapshot) + " | zfs recv " + dest.Path() + "/" + src.Box() + "/" + src.Path())
 | 
				
			||||||
					if err != nil {
 | 
										if err != nil {
 | 
				
			||||||
						if *debugFlag {
 | 
											if *debugFlag {
 | 
				
			||||||
							log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err)
 | 
												log.Printf("AppConfig.SendSnapshots : %s : Sending snapshot on %s from %s failed (%s)", a.Name, dest.Box(), string(sNextSnapshot), err)
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						return err
 | 
											return
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										isLastSnapshot, _ = cfg.Box[src.Box()].ZFSIsLastSnapshot(sNextSnapshot)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
						err = nil
 | 
				
			||||||
	return nil
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (a AppConfig) CleanupSnapshot() error {
 | 
					func (a AppConfig) CleanupSnapshot() error {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										157
									
								
								box.go
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								box.go
									
									
									
									
									
								
							@ -17,28 +17,165 @@ type Box struct {
 | 
				
			|||||||
	zfs  *ZFSConfig
 | 
						zfs  *ZFSConfig
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Box) ZFSGetLastSnapshot(path string) (s Snapshot, err error) {
 | 
					func (b *Box) ZFSGetLastSnapshot(path string) (last Snapshot, err error) {
 | 
				
			||||||
	return b.ssh.getLastSnapshot(path)
 | 
						err = b.SnapshotInitialize()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Box) ZFSIsLastSnapshot(s Snapshot) bool {
 | 
						if *debugFlag {
 | 
				
			||||||
	return b.ssh.isLastSnapshot(s)
 | 
							log.Printf("Box.ZFSGetLastSnapshot : %s : Start %s (%d snapshots)", b.Name, path, len(b.zfs.SnapshotList))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Box) ZFSGetFirstSnapshot(path string) (s Snapshot, err error) {
 | 
						for _, v := range b.zfs.SnapshotList {
 | 
				
			||||||
	return b.ssh.getFirstSnapshot(path)
 | 
							if v.Path() == path {
 | 
				
			||||||
 | 
								last = v
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(string(last)) == 0 {
 | 
				
			||||||
 | 
							err = fmt.Errorf("no snapshot")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *Box) ZFSIsLastSnapshot(src Snapshot) (is bool, err error) {
 | 
				
			||||||
 | 
						err = b.SnapshotInitialize()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if *debugFlag {
 | 
				
			||||||
 | 
							log.Printf("SSHConfig.isLastSnapshot : %s : Start %s", b.Name, string(src))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = b.ZFSGetNextSnapshot(src)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if err.Error() == "no snapshot" {
 | 
				
			||||||
 | 
								is = true
 | 
				
			||||||
 | 
								err = nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							is = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *Box) ZFSGetFirstSnapshot(path string) (first Snapshot, err error) {
 | 
				
			||||||
 | 
						err = b.SnapshotInitialize()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if *debugFlag {
 | 
				
			||||||
 | 
							log.Printf("SSHConfig.getFirstSnapshot : Start %s:%s", b.Name, path)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, v := range b.zfs.SnapshotList {
 | 
				
			||||||
 | 
							if v.Path() == path {
 | 
				
			||||||
 | 
								first = v
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = fmt.Errorf("no snapshot")
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Box) ZFSGetNextSnapshot(src Snapshot) (next Snapshot, err error) {
 | 
					func (b *Box) ZFSGetNextSnapshot(src Snapshot) (next Snapshot, err error) {
 | 
				
			||||||
	return b.ssh.getNextSnapshot(src)
 | 
						err = b.SnapshotInitialize()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if *debugFlag {
 | 
				
			||||||
 | 
							log.Printf("Box.ZFSGetNextSnapshot : Start %s:%s", b.Name, string(src))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for id, v := range b.zfs.SnapshotList {
 | 
				
			||||||
 | 
							if v == src {
 | 
				
			||||||
 | 
								if len(b.zfs.SnapshotList) > id+1 {
 | 
				
			||||||
 | 
									next = b.zfs.SnapshotList[id+1]
 | 
				
			||||||
 | 
									if next.Path() == src.Path() {
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										err = fmt.Errorf("no snapshot")
 | 
				
			||||||
 | 
										return
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									err = fmt.Errorf("no snapshot")
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = fmt.Errorf("no snapshot")
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Box) ZFSUpdateSnapshotList() (err error) {
 | 
					func (b *Box) ZFSUpdateSnapshotList() (err error) {
 | 
				
			||||||
	return b.ssh.getSnapshotList()
 | 
						b.zfs.M.Lock()
 | 
				
			||||||
 | 
						if b.zfs.SnapshotDeleted || b.zfs.SnapshotAdded {
 | 
				
			||||||
 | 
							b.zfs.SnapshotInitialized = false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						b.zfs.M.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = b.SnapshotInitialize()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Box) ZFSGetSnapshotList() []Snapshot {
 | 
					func (b *Box) ZFSGetSnapshotList() (snaps []Snapshot, err error) {
 | 
				
			||||||
	return b.ssh.snapshot
 | 
						err = b.SnapshotInitialize()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b.zfs.M.Lock()
 | 
				
			||||||
 | 
						defer b.zfs.M.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						snaps = b.zfs.SnapshotList
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (b *Box) SnapshotInitialize() (err error) {
 | 
				
			||||||
 | 
						b.zfs.M.Lock()
 | 
				
			||||||
 | 
						defer b.zfs.M.Unlock()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if b.zfs.SnapshotInitialized {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if *debugFlag {
 | 
				
			||||||
 | 
							log.Printf("Box.SnapshotInitialize : %s : Start", b.Name)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b.zfs.SnapshotList = make([]Snapshot, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var buf *bytes.Buffer
 | 
				
			||||||
 | 
						buf, err = b.SSHExec("zfs list -H -t snapshot -o name")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						csvReader := csv.NewReader(buf)
 | 
				
			||||||
 | 
						csvReader.Comma = '\t'
 | 
				
			||||||
 | 
						csvReader.FieldsPerRecord = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						csvData, err := csvReader.ReadAll()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							if *debugFlag {
 | 
				
			||||||
 | 
								log.Printf("Box.SnapshotInitialize : %s : csvReader.ReadAll() : %s", b.Name, err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, rec := range csvData {
 | 
				
			||||||
 | 
							b.zfs.SnapshotList = append(b.zfs.SnapshotList, Snapshot(rec[0]))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if *debugFlag {
 | 
				
			||||||
 | 
							log.Printf("Box.SnapshotInitialize : %s : read %d zfs snapshots", b.Name, len(b.zfs.SnapshotList))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b.zfs.SnapshotInitialized = true
 | 
				
			||||||
 | 
						b.zfs.SnapshotAdded = false
 | 
				
			||||||
 | 
						b.zfs.SnapshotDeleted = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (b *Box) ZFSUpdateList() (err error) {
 | 
					func (b *Box) ZFSUpdateList() (err error) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										128
									
								
								ssh.go
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								ssh.go
									
									
									
									
									
								
							@ -2,8 +2,6 @@ package main
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"encoding/csv"
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"golang.org/x/crypto/ssh"
 | 
						"golang.org/x/crypto/ssh"
 | 
				
			||||||
@ -15,135 +13,9 @@ type SSHConfig struct {
 | 
				
			|||||||
	client   *ssh.Client
 | 
						client   *ssh.Client
 | 
				
			||||||
	logged   bool
 | 
						logged   bool
 | 
				
			||||||
	name     string
 | 
						name     string
 | 
				
			||||||
	zfs      map[string]string
 | 
					 | 
				
			||||||
	snapshot []Snapshot
 | 
						snapshot []Snapshot
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (s *SSHConfig) getLastSnapshot(path string) (Snapshot, error) {
 | 
					 | 
				
			||||||
	if *debugFlag {
 | 
					 | 
				
			||||||
		log.Printf("SSHConfig.getLastSnapshot : Start %s:%s (%d snapshots)", s.name, path, len(s.snapshot))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var last Snapshot
 | 
					 | 
				
			||||||
	for _, v := range s.snapshot {
 | 
					 | 
				
			||||||
		if v.Path() == path {
 | 
					 | 
				
			||||||
			last = v
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			if len(string(last)) > 0 {
 | 
					 | 
				
			||||||
				return last, nil
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(string(last)) > 0 {
 | 
					 | 
				
			||||||
		return last, nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return last, fmt.Errorf("no snapshot")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *SSHConfig) isLastSnapshot(snapshot Snapshot) bool {
 | 
					 | 
				
			||||||
	if *debugFlag {
 | 
					 | 
				
			||||||
		log.Printf("SSHConfig.isLastSnapshot : Start %s:%s", s.name, string(snapshot))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	_, err := s.getNextSnapshot(snapshot)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return true
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *SSHConfig) getFirstSnapshot(path string) (Snapshot, error) {
 | 
					 | 
				
			||||||
	if *debugFlag {
 | 
					 | 
				
			||||||
		log.Printf("SSHConfig.getFirstSnapshot : Start %s:%s", s.name, path)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var first Snapshot
 | 
					 | 
				
			||||||
	for _, v := range s.snapshot {
 | 
					 | 
				
			||||||
		if v.Path() == path {
 | 
					 | 
				
			||||||
			first = v
 | 
					 | 
				
			||||||
			if *debugFlag {
 | 
					 | 
				
			||||||
				log.Printf("SSHConfig.getFirstSnapshot : Return %s", string(first))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return first, nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return first, fmt.Errorf("no snapshot")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *SSHConfig) getNextSnapshot(snapshot Snapshot) (Snapshot, error) {
 | 
					 | 
				
			||||||
	if *debugFlag {
 | 
					 | 
				
			||||||
		log.Printf("SSHConfig.getNextSnapshot : Start %s:%s", s.name, string(snapshot))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var next Snapshot
 | 
					 | 
				
			||||||
	for id, v := range s.snapshot {
 | 
					 | 
				
			||||||
		if v == snapshot {
 | 
					 | 
				
			||||||
			if len(s.snapshot) > id+1 {
 | 
					 | 
				
			||||||
				next = s.snapshot[id+1]
 | 
					 | 
				
			||||||
				if next.Path() == snapshot.Path() {
 | 
					 | 
				
			||||||
					return next, nil
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					return next, fmt.Errorf("no snapshot")
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				return next, fmt.Errorf("no snapshot")
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return next, fmt.Errorf("no snapshot")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *SSHConfig) getSnapshotList() error {
 | 
					 | 
				
			||||||
	if *debugFlag {
 | 
					 | 
				
			||||||
		log.Printf("SSHConfig.getSnapshotList : %s : Start", s.name)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if !s.logged {
 | 
					 | 
				
			||||||
		return fmt.Errorf("Client %s not logged in.", s.name)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	session, err := s.client.NewSession()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		if *debugFlag {
 | 
					 | 
				
			||||||
			log.Printf("SSHConfig.getSnapshotList : %s : client.NewSession() : %s", s.name, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var b bytes.Buffer
 | 
					 | 
				
			||||||
	session.Stdout = &b
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = session.Run("TZ=\"" + cfg.Timezone + "\" zfs list -H -t snapshot -o name")
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		if *debugFlag {
 | 
					 | 
				
			||||||
			log.Printf("SSHConfig.getSnapshotList : %s : session.Run() : %s", s.name, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	s.snapshot = make([]Snapshot, 0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	csvReader := csv.NewReader(&b)
 | 
					 | 
				
			||||||
	csvReader.Comma = '\t'
 | 
					 | 
				
			||||||
	csvReader.FieldsPerRecord = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	csvData, err := csvReader.ReadAll()
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		if *debugFlag {
 | 
					 | 
				
			||||||
			log.Printf("SSHConfig.getSnapshotList : %s : csvReader.ReadAll() : %s", s.name, err)
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, rec := range csvData {
 | 
					 | 
				
			||||||
		s.snapshot = append(s.snapshot, Snapshot(rec[0]))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if *debugFlag {
 | 
					 | 
				
			||||||
		log.Printf("SSHConfig.getSnapshotList : %s : read %d zfs snapshots", s.name, len(s.snapshot))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	session.Close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *SSHConfig) exec(cmd string) (b *bytes.Buffer, err error) {
 | 
					func (s *SSHConfig) exec(cmd string) (b *bytes.Buffer, err error) {
 | 
				
			||||||
	if *debugFlag {
 | 
						if *debugFlag {
 | 
				
			||||||
		log.Printf("SSHConfig.exec : %s : Start %s", s.name, cmd)
 | 
							log.Printf("SSHConfig.exec : %s : Start %s", s.name, cmd)
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
// Code generated by version.sh (@generated) DO NOT EDIT.
 | 
					// Code generated by version.sh (@generated) DO NOT EDIT.
 | 
				
			||||||
package main
 | 
					package main
 | 
				
			||||||
var githash = "2704149"
 | 
					var githash = "e192906"
 | 
				
			||||||
var buildstamp = "2021-11-14_07:57:44"
 | 
					var buildstamp = "2021-11-14_09:20:16"
 | 
				
			||||||
var commits = "20"
 | 
					var commits = "21"
 | 
				
			||||||
var version = "2704149-b20 - 2021-11-14_07:57:44"
 | 
					var version = "e192906-b21 - 2021-11-14_09:20:16"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user