// NewStore creates a new store server serving snaps from the given top directory and assertions from topDir/asserts. If assertFallback is true missing assertions are looked up in the main online store. func NewStore(topDir, addr string, assertFallback bool) *Store { mux := http.NewServeMux() var sto *store.Store if assertFallback { sto = store.New(nil, nil) } store := &Store{ blobDir: topDir, assertDir: filepath.Join(topDir, "asserts"), assertFallback: assertFallback, fallback: sto, url: fmt.Sprintf("http://%s", addr), srv: &graceful.Server{ Timeout: 2 * time.Second, Server: &http.Server{ Addr: addr, Handler: mux, }, }, } mux.HandleFunc("/", rootEndpoint) mux.HandleFunc("/search", store.searchEndpoint) mux.HandleFunc("/snaps/details/", store.detailsEndpoint) mux.HandleFunc("/snaps/metadata", store.bulkEndpoint) mux.Handle("/download/", http.StripPrefix("/download/", http.FileServer(http.Dir(topDir)))) mux.HandleFunc("/assertions/", store.assertionsEndpoint) return store }
func (s *SnapSuite) TestKnownRemote(c *check.C) { var server *httptest.Server restorer := snap.MockStoreNew(func(cfg *store.Config, auth auth.AuthContext) *store.Store { if cfg == nil { cfg = store.DefaultConfig() } serverURL, err := url.Parse(server.URL + "/assertions/") c.Assert(err, check.IsNil) cfg.AssertionsURI = serverURL return store.New(cfg, auth) }) defer restorer() n := 0 server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { switch n { case 0: c.Check(r.Method, check.Equals, "GET") c.Check(r.URL.Path, check.Equals, "/assertions/model/16/canonical/pi99") fmt.Fprintln(w, mockModelAssertion) default: c.Fatalf("expected to get 1 requests, now on %d", n+1) } n++ })) rest, err := snap.Parser().ParseArgs([]string{"known", "--remote", "model", "series=16", "brand-id=canonical", "model=pi99"}) c.Assert(err, check.IsNil) c.Assert(rest, check.DeepEquals, []string{}) c.Check(s.Stdout(), check.Equals, mockModelAssertion) c.Check(s.Stderr(), check.Equals, "") }
func makeStore(model *asserts.Model) Store { cfg := store.DefaultConfig() cfg.Architecture = model.Architecture() cfg.Series = model.Series() cfg.StoreID = model.Store() return store.New(cfg, nil) }
func (x *cmdDownload) Execute(args []string) error { if err := x.setChannelFromCommandline(); err != nil { return err } if len(args) > 0 { return ErrExtraArgs } var revision snap.Revision if x.Revision == "" { revision = snap.R(0) } else { var err error revision, err = snap.ParseRevision(x.Revision) if err != nil { return err } } snapName := string(x.Positional.Snap) // FIXME: set auth context var authContext auth.AuthContext var user *auth.UserState sto := store.New(nil, authContext) // we always allow devmode for downloads devMode := true dlOpts := image.DownloadOptions{ TargetDir: "", // cwd DevMode: devMode, Channel: x.Channel, User: user, } fmt.Fprintf(Stderr, i18n.G("Fetching snap %q\n"), snapName) snapPath, snapInfo, err := image.DownloadSnap(sto, snapName, revision, &dlOpts) if err != nil { return err } fmt.Fprintf(Stderr, i18n.G("Fetching assertions for %q\n"), snapName) err = fetchSnapAssertions(sto, snapPath, snapInfo, &dlOpts) if err != nil { return err } return nil }
func MakeFakeRefreshForSnaps(snaps []string, blobDir string) error { storePrivKey, _ := assertstest.ReadPrivKey(systestkeys.TestStorePrivKey) db, err := asserts.OpenDatabase(&asserts.DatabaseConfig{ KeypairManager: asserts.NewMemoryKeypairManager(), Backstore: asserts.NewMemoryBackstore(), Trusted: sysdb.Trusted(), }) if err != nil { return err } // for signing db.ImportKey(storePrivKey) // XXX: ideally for consistency we should talk to the local snapd // but this allows us to go working until snapd itself // start being fully assertion using sto := store.New(nil, nil) retrieve := func(ref *asserts.Ref) (asserts.Assertion, error) { return sto.Assertion(ref.Type, ref.PrimaryKey, nil) } save := func(a asserts.Assertion) error { err := db.Add(a) if err != nil { if _, ok := err.(*asserts.RevisionError); !ok { return err } } return writeAssert(a, blobDir) } f := asserts.NewFetcher(db, retrieve, save) for _, snap := range snaps { if err := makeFakeRefreshForSnap(snap, blobDir, db, f); err != nil { return err } } return nil }
func (ms *mgrsSuite) mockStore(c *C) *httptest.Server { var baseURL string fillHit := func() string { snapf, err := snap.Open(ms.serveSnapPath) if err != nil { panic(err) } info, err := snap.ReadInfoFromSnapFile(snapf, nil) if err != nil { panic(err) } hit := strings.Replace(fooSearchHit, "@URL@", baseURL+"/snap", -1) hit = strings.Replace(hit, "@ICON@", baseURL+"/icon", -1) hit = strings.Replace(hit, "@VERSION@", info.Version, -1) hit = strings.Replace(hit, "@REVISION@", ms.serveRevision, -1) return hit } mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.HasPrefix(r.URL.Path, "/assertions/") { comps := strings.Split(r.URL.Path, "/") ref := &asserts.Ref{ Type: asserts.Type(comps[2]), PrimaryKey: comps[3:], } a, err := ref.Resolve(ms.storeSigning.Find) if err == asserts.ErrNotFound { w.Header().Set("Content-Type", "application/json") w.WriteHeader(404) w.Write([]byte(`{"status": 404}`)) return } if err != nil { panic(err) } w.Header().Set("Content-Type", asserts.MediaType) w.WriteHeader(200) w.Write(asserts.Encode(a)) return } switch r.URL.Path { case "/details/foo": w.WriteHeader(http.StatusOK) io.WriteString(w, fillHit()) case "/metadata": w.WriteHeader(http.StatusOK) output := `{ "_embedded": { "clickindex:package": [@HIT@] } }` output = strings.Replace(output, "@HIT@", fillHit(), 1) io.WriteString(w, output) case "/snap": snapR, err := os.Open(ms.serveSnapPath) if err != nil { panic(err) } io.Copy(w, snapR) default: panic("unexpected url path: " + r.URL.Path) } })) c.Assert(mockServer, NotNil) baseURL = mockServer.URL detailsURL, err := url.Parse(baseURL + "/details/") c.Assert(err, IsNil) bulkURL, err := url.Parse(baseURL + "/metadata") c.Assert(err, IsNil) assertionsURL, err := url.Parse(baseURL + "/assertions/") c.Assert(err, IsNil) storeCfg := store.Config{ DetailsURI: detailsURL, BulkURI: bulkURL, AssertionsURI: assertionsURL, } mStore := store.New(&storeCfg, nil) st := ms.o.State() st.Lock() snapstate.ReplaceStore(ms.o.State(), mStore) st.Unlock() return mockServer }
func (ms *mgrsSuite) mockStore(c *C) *httptest.Server { var baseURL string fillHit := func(name string) string { snapf, err := snap.Open(ms.serveSnapPath[name]) if err != nil { panic(err) } info, err := snap.ReadInfoFromSnapFile(snapf, nil) if err != nil { panic(err) } hit := strings.Replace(searchHit, "@URL@", baseURL+"/snap/"+name, -1) hit = strings.Replace(hit, "@NAME@", name, -1) hit = strings.Replace(hit, "@SNAPID@", fakeSnapID(name), -1) hit = strings.Replace(hit, "@ICON@", baseURL+"/icon", -1) hit = strings.Replace(hit, "@VERSION@", info.Version, -1) hit = strings.Replace(hit, "@REVISION@", ms.serveRevision[name], -1) return hit } mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { comps := strings.Split(r.URL.Path, "/") if len(comps) == 0 { panic("unexpected url path: " + r.URL.Path) } switch comps[1] { case "assertions": ref := &asserts.Ref{ Type: asserts.Type(comps[2]), PrimaryKey: comps[3:], } a, err := ref.Resolve(ms.storeSigning.Find) if err == asserts.ErrNotFound { w.Header().Set("Content-Type", "application/json") w.WriteHeader(404) w.Write([]byte(`{"status": 404}`)) return } if err != nil { panic(err) } w.Header().Set("Content-Type", asserts.MediaType) w.WriteHeader(200) w.Write(asserts.Encode(a)) return case "details": w.WriteHeader(http.StatusOK) io.WriteString(w, fillHit(comps[2])) case "metadata": dec := json.NewDecoder(r.Body) var input struct { Snaps []struct { SnapID string `json:"snap_id"` Revision int `json:"revision"` } `json:"snaps"` } err := dec.Decode(&input) if err != nil { panic(err) } var hits []json.RawMessage for _, s := range input.Snaps { name := ms.serveIDtoName[s.SnapID] if snap.R(s.Revision) == snap.R(ms.serveRevision[name]) { continue } hits = append(hits, json.RawMessage(fillHit(name))) } w.WriteHeader(http.StatusOK) output, err := json.Marshal(map[string]interface{}{ "_embedded": map[string]interface{}{ "clickindex:package": hits, }, }) if err != nil { panic(err) } w.Write(output) case "snap": snapR, err := os.Open(ms.serveSnapPath[comps[2]]) if err != nil { panic(err) } io.Copy(w, snapR) default: panic("unexpected url path: " + r.URL.Path) } })) c.Assert(mockServer, NotNil) baseURL = mockServer.URL detailsURL, err := url.Parse(baseURL + "/details/") c.Assert(err, IsNil) bulkURL, err := url.Parse(baseURL + "/metadata") c.Assert(err, IsNil) assertionsURL, err := url.Parse(baseURL + "/assertions/") c.Assert(err, IsNil) storeCfg := store.Config{ DetailsURI: detailsURL, BulkURI: bulkURL, AssertionsURI: assertionsURL, } mStore := store.New(&storeCfg, nil) st := ms.o.State() st.Lock() snapstate.ReplaceStore(ms.o.State(), mStore) st.Unlock() return mockServer }