| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | package reload
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							|  |  |  | 	"crypto/md5"
 | 
					
						
							| 
									
										
										
										
											2019-02-17 14:57:36 +00:00
										 |  |  | 	"sync"
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 	"time"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/mholt/caddy"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // reload periodically checks if the Corefile has changed, and reloads if so
 | 
					
						
							| 
									
										
										
										
											2018-02-02 13:15:56 -05:00
										 |  |  | const (
 | 
					
						
							|  |  |  | 	unused    = 0
 | 
					
						
							|  |  |  | 	maybeUsed = 1
 | 
					
						
							|  |  |  | 	used      = 2
 | 
					
						
							|  |  |  | )
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | type reload struct {
 | 
					
						
							| 
									
										
										
										
											2019-02-17 14:57:36 +00:00
										 |  |  | 	dur  time.Duration
 | 
					
						
							|  |  |  | 	u    int
 | 
					
						
							|  |  |  | 	mtx  sync.RWMutex
 | 
					
						
							|  |  |  | 	quit chan bool
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *reload) setUsage(u int) {
 | 
					
						
							|  |  |  | 	r.mtx.Lock()
 | 
					
						
							|  |  |  | 	defer r.mtx.Unlock()
 | 
					
						
							|  |  |  | 	r.u = u
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *reload) usage() int {
 | 
					
						
							|  |  |  | 	r.mtx.RLock()
 | 
					
						
							|  |  |  | 	defer r.mtx.RUnlock()
 | 
					
						
							|  |  |  | 	return r.u
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *reload) setInterval(i time.Duration) {
 | 
					
						
							|  |  |  | 	r.mtx.Lock()
 | 
					
						
							|  |  |  | 	defer r.mtx.Unlock()
 | 
					
						
							|  |  |  | 	r.dur = i
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r *reload) interval() time.Duration {
 | 
					
						
							|  |  |  | 	r.mtx.RLock()
 | 
					
						
							|  |  |  | 	defer r.mtx.RUnlock()
 | 
					
						
							|  |  |  | 	return r.dur
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func hook(event caddy.EventName, info interface{}) error {
 | 
					
						
							|  |  |  | 	if event != caddy.InstanceStartupEvent {
 | 
					
						
							|  |  |  | 		return nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if reload is removed from the Corefile, then the hook
 | 
					
						
							|  |  |  | 	// is still registered but setup is never called again
 | 
					
						
							|  |  |  | 	// so we need a flag to tell us not to reload
 | 
					
						
							| 
									
										
										
										
											2019-02-17 14:57:36 +00:00
										 |  |  | 	if r.usage() == unused {
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 		return nil
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// this should be an instance. ok to panic if not
 | 
					
						
							| 
									
										
										
										
											2018-02-02 13:15:56 -05:00
										 |  |  | 	instance := info.(*caddy.Instance)
 | 
					
						
							|  |  |  | 	md5sum := md5.Sum(instance.Caddyfile().Body())
 | 
					
						
							| 
									
										
										
										
											2018-04-19 07:41:56 +01:00
										 |  |  | 	log.Infof("Running configuration MD5 = %x\n", md5sum)
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	go func() {
 | 
					
						
							| 
									
										
										
										
											2019-02-17 14:57:36 +00:00
										 |  |  | 		tick := time.NewTicker(r.interval())
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for {
 | 
					
						
							|  |  |  | 			select {
 | 
					
						
							|  |  |  | 			case <-tick.C:
 | 
					
						
							| 
									
										
										
										
											2018-02-02 13:15:56 -05:00
										 |  |  | 				corefile, err := caddy.LoadCaddyfile(instance.Caddyfile().ServerType())
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 				if err != nil {
 | 
					
						
							|  |  |  | 					continue
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 				s := md5.Sum(corefile.Body())
 | 
					
						
							| 
									
										
										
										
											2018-02-02 13:15:56 -05:00
										 |  |  | 				if s != md5sum {
 | 
					
						
							|  |  |  | 					// Let not try to restart with the same file, even though it is wrong.
 | 
					
						
							|  |  |  | 					md5sum = s
 | 
					
						
							|  |  |  | 					// now lets consider that plugin will not be reload, unless appear in next config file
 | 
					
						
							|  |  |  | 					// change status iof usage will be reset in setup if the plugin appears in config file
 | 
					
						
							| 
									
										
										
										
											2019-02-17 14:57:36 +00:00
										 |  |  | 					r.setUsage(maybeUsed)
 | 
					
						
							| 
									
										
										
										
											2018-02-02 13:15:56 -05:00
										 |  |  | 					_, err := instance.Restart(corefile)
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 					if err != nil {
 | 
					
						
							| 
									
										
										
										
											2019-01-19 11:23:13 +00:00
										 |  |  | 						log.Errorf("Corefile changed but reload failed: %s", err)
 | 
					
						
							| 
									
										
										
										
											2019-06-26 09:38:46 +03:00
										 |  |  | 						FailedCount.Add(1)
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 						continue
 | 
					
						
							|  |  |  | 					}
 | 
					
						
							| 
									
										
										
										
											2018-02-02 13:15:56 -05:00
										 |  |  | 					// we are done, if the plugin was not set used, then it is not.
 | 
					
						
							| 
									
										
										
										
											2019-02-17 14:57:36 +00:00
										 |  |  | 					if r.usage() == maybeUsed {
 | 
					
						
							|  |  |  | 						r.setUsage(unused)
 | 
					
						
							| 
									
										
										
										
											2018-02-02 13:15:56 -05:00
										 |  |  | 					}
 | 
					
						
							| 
									
										
										
										
											2018-01-27 05:42:57 -05:00
										 |  |  | 					return
 | 
					
						
							|  |  |  | 				}
 | 
					
						
							|  |  |  | 			case <-r.quit:
 | 
					
						
							|  |  |  | 				return
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil
 | 
					
						
							|  |  |  | }
 |