github.com/dlintw/docker@v1.5.0-rc4/trust/trusts.go (about) 1 package trust 2 3 import ( 4 "crypto/x509" 5 "errors" 6 "io/ioutil" 7 "net/http" 8 "net/url" 9 "os" 10 "path" 11 "path/filepath" 12 "sync" 13 "time" 14 15 log "github.com/Sirupsen/logrus" 16 "github.com/docker/libtrust/trustgraph" 17 ) 18 19 type TrustStore struct { 20 path string 21 caPool *x509.CertPool 22 graph trustgraph.TrustGraph 23 expiration time.Time 24 fetcher *time.Timer 25 fetchTime time.Duration 26 autofetch bool 27 httpClient *http.Client 28 baseEndpoints map[string]*url.URL 29 30 sync.RWMutex 31 } 32 33 // defaultFetchtime represents the starting duration to wait between 34 // fetching sections of the graph. Unsuccessful fetches should 35 // increase time between fetching. 36 const defaultFetchtime = 45 * time.Second 37 38 var baseEndpoints = map[string]string{"official": "https://dvjy3tqbc323p.cloudfront.net/trust/official.json"} 39 40 func NewTrustStore(path string) (*TrustStore, error) { 41 abspath, err := filepath.Abs(path) 42 if err != nil { 43 return nil, err 44 } 45 46 // Create base graph url map 47 endpoints := map[string]*url.URL{} 48 for name, endpoint := range baseEndpoints { 49 u, err := url.Parse(endpoint) 50 if err != nil { 51 return nil, err 52 } 53 endpoints[name] = u 54 } 55 56 // Load grant files 57 t := &TrustStore{ 58 path: abspath, 59 caPool: nil, 60 httpClient: &http.Client{}, 61 fetchTime: time.Millisecond, 62 baseEndpoints: endpoints, 63 } 64 65 err = t.reload() 66 if err != nil { 67 return nil, err 68 } 69 70 return t, nil 71 } 72 73 func (t *TrustStore) reload() error { 74 t.Lock() 75 defer t.Unlock() 76 77 matches, err := filepath.Glob(filepath.Join(t.path, "*.json")) 78 if err != nil { 79 return err 80 } 81 statements := make([]*trustgraph.Statement, len(matches)) 82 for i, match := range matches { 83 f, err := os.Open(match) 84 if err != nil { 85 return err 86 } 87 statements[i], err = trustgraph.LoadStatement(f, nil) 88 if err != nil { 89 f.Close() 90 return err 91 } 92 f.Close() 93 } 94 if len(statements) == 0 { 95 if t.autofetch { 96 log.Debugf("No grants, fetching") 97 t.fetcher = time.AfterFunc(t.fetchTime, t.fetch) 98 } 99 return nil 100 } 101 102 grants, expiration, err := trustgraph.CollapseStatements(statements, true) 103 if err != nil { 104 return err 105 } 106 107 t.expiration = expiration 108 t.graph = trustgraph.NewMemoryGraph(grants) 109 log.Debugf("Reloaded graph with %d grants expiring at %s", len(grants), expiration) 110 111 if t.autofetch { 112 nextFetch := expiration.Sub(time.Now()) 113 if nextFetch < 0 { 114 nextFetch = defaultFetchtime 115 } else { 116 nextFetch = time.Duration(0.8 * (float64)(nextFetch)) 117 } 118 t.fetcher = time.AfterFunc(nextFetch, t.fetch) 119 } 120 121 return nil 122 } 123 124 func (t *TrustStore) fetchBaseGraph(u *url.URL) (*trustgraph.Statement, error) { 125 req := &http.Request{ 126 Method: "GET", 127 URL: u, 128 Proto: "HTTP/1.1", 129 ProtoMajor: 1, 130 ProtoMinor: 1, 131 Header: make(http.Header), 132 Body: nil, 133 Host: u.Host, 134 } 135 136 resp, err := t.httpClient.Do(req) 137 if err != nil { 138 return nil, err 139 } 140 if resp.StatusCode == 404 { 141 return nil, errors.New("base graph does not exist") 142 } 143 144 defer resp.Body.Close() 145 146 return trustgraph.LoadStatement(resp.Body, t.caPool) 147 } 148 149 // fetch retrieves updated base graphs. This function cannot error, it 150 // should only log errors 151 func (t *TrustStore) fetch() { 152 t.Lock() 153 defer t.Unlock() 154 155 if t.autofetch && t.fetcher == nil { 156 // Do nothing ?? 157 return 158 } 159 160 fetchCount := 0 161 for bg, ep := range t.baseEndpoints { 162 statement, err := t.fetchBaseGraph(ep) 163 if err != nil { 164 log.Infof("Trust graph fetch failed: %s", err) 165 continue 166 } 167 b, err := statement.Bytes() 168 if err != nil { 169 log.Infof("Bad trust graph statement: %s", err) 170 continue 171 } 172 // TODO check if value differs 173 err = ioutil.WriteFile(path.Join(t.path, bg+".json"), b, 0600) 174 if err != nil { 175 log.Infof("Error writing trust graph statement: %s", err) 176 } 177 fetchCount++ 178 } 179 log.Debugf("Fetched %d base graphs at %s", fetchCount, time.Now()) 180 181 if fetchCount > 0 { 182 go func() { 183 err := t.reload() 184 if err != nil { 185 log.Infof("Reload of trust graph failed: %s", err) 186 } 187 }() 188 t.fetchTime = defaultFetchtime 189 t.fetcher = nil 190 } else if t.autofetch { 191 maxTime := 10 * defaultFetchtime 192 t.fetchTime = time.Duration(1.5 * (float64)(t.fetchTime+time.Second)) 193 if t.fetchTime > maxTime { 194 t.fetchTime = maxTime 195 } 196 t.fetcher = time.AfterFunc(t.fetchTime, t.fetch) 197 } 198 }