Esempio n. 1
0
// 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
}
Esempio n. 2
0
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, "")
}
Esempio n. 3
0
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)
}
Esempio n. 4
0
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
}
Esempio n. 5
0
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
}
Esempio n. 6
0
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
}
Esempio n. 7
0
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
}