func (s *InternalClientSuite) TestListResources(c *gc.C) {
	fp, err := resource.GenerateFingerprint(strings.NewReader("data"))
	c.Assert(err, jc.ErrorIsNil)

	stable := params.Resource{
		Name:        "name",
		Type:        "file",
		Path:        "foo.zip",
		Description: "something",
		Origin:      "store",
		Revision:    5,
		Fingerprint: fp.Bytes(),
		Size:        4,
	}
	dev := params.Resource{
		Name:        "name2",
		Type:        "file",
		Path:        "bar.zip",
		Description: "something",
		Origin:      "store",
		Revision:    7,
		Fingerprint: fp.Bytes(),
		Size:        4,
	}
	s.lowLevel.ReturnListResourcesStable = map[string][]params.Resource{
		"cs:quantal/foo-1": []params.Resource{stable},
	}
	s.lowLevel.ReturnListResourcesDev = map[string][]params.Resource{
		"cs:quantal/bar-1": []params.Resource{dev},
	}

	client := Client{lowLevel: s.lowLevel}
	foo := charm.MustParseURL("cs:quantal/foo-1")
	bar := charm.MustParseURL("cs:quantal/bar-1")

	ret, err := client.ListResources([]CharmID{{
		URL:     foo,
		Channel: "stable",
	}, {
		URL:     bar,
		Channel: "development",
	}})
	c.Assert(err, jc.ErrorIsNil)

	stableOut, err := params.API2Resource(stable)
	c.Assert(err, jc.ErrorIsNil)

	devOut, err := params.API2Resource(dev)
	c.Assert(err, jc.ErrorIsNil)

	c.Assert(ret, gc.DeepEquals, [][]resource.Resource{
		{stableOut},
		{devOut},
	})
	s.lowLevel.stableStub.CheckCall(c, 0, "ListResources", params.StableChannel, []*charm.URL{foo})
	s.lowLevel.devStub.CheckCall(c, 0, "ListResources", params.DevelopmentChannel, []*charm.URL{bar})
}
Example #2
0
File: client.go Project: bac/juju
// GetResource returns the data (bytes) and metadata for a resource from the charmstore.
func (c Client) GetResource(req ResourceRequest) (data ResourceData, err error) {
	if err := c.jar.Activate(req.Charm); err != nil {
		return ResourceData{}, errors.Trace(err)
	}
	defer c.jar.Deactivate()
	meta, err := c.csWrapper.ResourceMeta(req.Channel, req.Charm, req.Name, req.Revision)

	if err != nil {
		return ResourceData{}, errors.Trace(err)
	}
	data.Resource, err = csparams.API2Resource(meta)
	if err != nil {
		return ResourceData{}, errors.Trace(err)
	}
	resData, err := c.csWrapper.GetResource(req.Channel, req.Charm, req.Name, req.Revision)
	if err != nil {
		return ResourceData{}, errors.Trace(err)
	}
	defer func() {
		if err != nil {
			resData.Close()
		}
	}()
	data.ReadCloser = resData.ReadCloser
	fpHash := data.Resource.Fingerprint.String()
	if resData.Hash != fpHash {
		return ResourceData{},
			errors.Errorf("fingerprint for data (%s) does not match fingerprint in metadata (%s)", resData.Hash, fpHash)
	}
	if resData.Size != data.Resource.Size {
		return ResourceData{},
			errors.Errorf("size for data (%d) does not match size in metadata (%d)", resData.Size, data.Resource.Size)
	}
	return data, nil
}
Example #3
0
func (s *ClientSuite) TestResourceInfo(c *gc.C) {
	fp, err := resource.GenerateFingerprint(strings.NewReader("data"))
	c.Assert(err, jc.ErrorIsNil)
	apiRes := params.Resource{
		Name:        "name",
		Type:        "file",
		Path:        "foo.zip",
		Description: "something",
		Origin:      "store",
		Revision:    5,
		Fingerprint: fp.Bytes(),
		Size:        4,
	}
	s.wrapper.ReturnResourceMeta = apiRes

	client, err := newCachingClient(s.cache, nil, s.wrapper.makeWrapper)
	c.Assert(err, jc.ErrorIsNil)

	req := ResourceRequest{
		Charm:    charm.MustParseURL("cs:mysql"),
		Channel:  params.StableChannel,
		Name:     "name",
		Revision: 5,
	}
	res, err := client.ResourceInfo(req)
	c.Assert(err, jc.ErrorIsNil)
	expected, err := params.API2Resource(apiRes)
	c.Assert(err, jc.ErrorIsNil)
	c.Check(res, gc.DeepEquals, expected)
	// call #0 is a call to makeWrapper
	s.wrapper.stub.CheckCall(c, 1, "ResourceMeta", params.StableChannel, req.Charm, req.Name, req.Revision)
}
Example #4
0
// GetResource returns the data (bytes) and metadata for a resource from the charmstore.
func (c Client) GetResource(id CharmID, resourceName string, revision int) (res charmresource.Resource, rc io.ReadCloser, err error) {
	defer func() {
		if err != nil && rc != nil {
			rc.Close()
		}
	}()
	meta, err := c.lowLevel.ResourceInfo(id.Channel, id.URL, resourceName, revision)
	if err != nil {
		return charmresource.Resource{}, nil, errors.Trace(err)
	}
	res, err = csparams.API2Resource(meta)
	if err != nil {
		return charmresource.Resource{}, nil, errors.Trace(err)
	}

	data, err := c.lowLevel.GetResource(id.Channel, id.URL, resourceName, revision)
	if err != nil {
		return charmresource.Resource{}, nil, errors.Trace(err)
	}
	fpHash := res.Fingerprint.String()
	if data.Hash != fpHash {
		return charmresource.Resource{}, nil,
			errors.Errorf("fingerprint for data (%s) does not match fingerprint in metadata (%s)", data.Hash, fpHash)
	}
	if data.Size != res.Size {
		return charmresource.Resource{}, nil,
			errors.Errorf("size for data (%d) does not match size in metadata (%d)", data.Size, res.Size)
	}

	return res, data.ReadCloser, nil
}
Example #5
0
// ListResources implements BaseClient by calling csclient.Client's ListResources function.
func (c Client) ListResources(charms []CharmID) ([][]charmresource.Resource, error) {
	requests := collate(charms)
	result := make([][]charmresource.Resource, len(charms))
	for channel, request := range requests {
		// we have to make one bulk call per channel, unfortunately
		resmap, err := c.lowLevel.ListResources(channel, request.ids)
		if err != nil {
			return nil, errors.Trace(err)
		}

		for i, id := range request.ids {
			resources, ok := resmap[id.String()]
			if !ok {
				continue
			}
			list := make([]charmresource.Resource, len(resources))
			for j, res := range resources {
				resource, err := csparams.API2Resource(res)
				if err != nil {
					return nil, errors.Annotatef(err, "got bad data from server for resource %q", res.Name)
				}
				list[j] = resource
			}
			idx := request.indices[i]
			result[idx] = list
		}
	}
	return result, nil
}
Example #6
0
File: client.go Project: bac/juju
func api2resources(res []csparams.Resource) ([]charmresource.Resource, error) {
	result := make([]charmresource.Resource, len(res))
	for i, r := range res {
		var err error
		result[i], err = csparams.API2Resource(r)
		if err != nil {
			return nil, errors.Trace(err)
		}
	}
	return result, nil
}
Example #7
0
// ResourceInfo returns the metadata info for the given resource from the charmstore.
func (c Client) ResourceInfo(id CharmID, resourceName string, revision int) (charmresource.Resource, error) {
	meta, err := c.lowLevel.ResourceInfo(id.Channel, id.URL, resourceName, revision)
	if err != nil {
		return charmresource.Resource{}, errors.Trace(err)
	}
	res, err := csparams.API2Resource(meta)
	if err != nil {
		return charmresource.Resource{}, errors.Trace(err)
	}
	return res, nil
}
Example #8
0
File: client.go Project: bac/juju
// ResourceInfo returns the metadata for the given resource from the charmstore.
func (c Client) ResourceInfo(req ResourceRequest) (charmresource.Resource, error) {
	if err := c.jar.Activate(req.Charm); err != nil {
		return charmresource.Resource{}, errors.Trace(err)
	}
	defer c.jar.Deactivate()
	meta, err := c.csWrapper.ResourceMeta(req.Channel, req.Charm, req.Name, req.Revision)
	if err != nil {
		return charmresource.Resource{}, errors.Trace(err)
	}
	res, err := csparams.API2Resource(meta)
	if err != nil {
		return charmresource.Resource{}, errors.Trace(err)
	}
	return res, nil
}
Example #9
0
func (s *ClientSuite) TestGetResource(c *gc.C) {
	fp, err := resource.GenerateFingerprint(strings.NewReader("data"))
	c.Assert(err, jc.ErrorIsNil)
	rc := ioutil.NopCloser(strings.NewReader("data"))
	s.wrapper.ReturnGetResource = csclient.ResourceData{
		ReadCloser: rc,
		Hash:       fp.String(),
		Size:       4,
	}
	apiRes := params.Resource{
		Name:        "name",
		Type:        "file",
		Path:        "foo.zip",
		Description: "something",
		Origin:      "store",
		Revision:    5,
		Fingerprint: fp.Bytes(),
		Size:        4,
	}
	s.wrapper.ReturnResourceMeta = apiRes

	client, err := newCachingClient(s.cache, nil, s.wrapper.makeWrapper)
	c.Assert(err, jc.ErrorIsNil)

	req := ResourceRequest{
		Charm:    charm.MustParseURL("cs:mysql"),
		Channel:  params.DevelopmentChannel,
		Name:     "name",
		Revision: 5,
	}
	data, err := client.GetResource(req)
	c.Assert(err, jc.ErrorIsNil)
	expected, err := params.API2Resource(apiRes)
	c.Assert(err, jc.ErrorIsNil)
	c.Check(data.Resource, gc.DeepEquals, expected)
	c.Check(data.ReadCloser, gc.DeepEquals, rc)
	// call #0 is a call to makeWrapper
	s.wrapper.stub.CheckCall(c, 1, "ResourceMeta", params.DevelopmentChannel, req.Charm, req.Name, req.Revision)
	s.wrapper.stub.CheckCall(c, 2, "GetResource", params.DevelopmentChannel, req.Charm, req.Name, req.Revision)
}
Example #10
0
func (s *LatestCharmInfoSuite) TestSuccess(c *gc.C) {
	spam := charm.MustParseURL("cs:quantal/spam-17")
	eggs := charm.MustParseURL("cs:quantal/eggs-2")
	ham := charm.MustParseURL("cs:quantal/ham-1")
	charms := []CharmID{
		{spam, "stable"},
		{eggs, "stable"},
		{ham, "stable"},
	}
	notFound := errors.New("not found")
	s.lowLevel.ReturnLatestStable = []charmrepo.CharmRevision{{
		Revision: 17,
	}, {
		Revision: 3,
	}, {
		Err: notFound,
	}}

	fakeRes := fakeParamsResource("foo", nil)

	s.lowLevel.ReturnListResourcesStable = map[string][]params.Resource{
		"cs:quantal/spam-17": []params.Resource{fakeRes},
	}

	uuid := "foobar"
	client := Client{lowLevel: s.lowLevel}
	results, err := LatestCharmInfo(client, charms, uuid)
	c.Assert(err, jc.ErrorIsNil)

	expectedIds := []*charm.URL{spam, eggs, ham}

	s.lowLevel.stableStub.CheckCallNames(c, "Latest", "ListResources")
	s.lowLevel.stableStub.CheckCall(c, 0, "Latest", params.StableChannel, expectedIds, map[string]string{"environment_uuid": uuid})
	s.lowLevel.stableStub.CheckCall(c, 1, "ListResources", params.StableChannel, expectedIds)

	expectedRes, err := params.API2Resource(fakeRes)
	c.Assert(err, jc.ErrorIsNil)

	timestamp := results[0].Timestamp
	results[2].Error = errors.Cause(results[2].Error)
	c.Check(results, jc.DeepEquals, []CharmInfoResult{{
		CharmInfo: CharmInfo{
			OriginalURL:    charm.MustParseURL("cs:quantal/spam-17"),
			Timestamp:      timestamp,
			LatestRevision: 17,
			LatestResources: []charmresource.Resource{
				expectedRes,
			},
		},
	}, {
		CharmInfo: CharmInfo{
			OriginalURL:    charm.MustParseURL("cs:quantal/eggs-2"),
			Timestamp:      timestamp,
			LatestRevision: 3,
		},
	}, {
		CharmInfo: CharmInfo{
			OriginalURL: charm.MustParseURL("cs:quantal/ham-1"),
			Timestamp:   timestamp,
		},
		Error: notFound,
	}})
}
Example #11
0
func (s *ClientSuite) TestListResources(c *gc.C) {
	fp, err := resource.GenerateFingerprint(strings.NewReader("data"))
	c.Assert(err, jc.ErrorIsNil)

	stable := params.Resource{
		Name:        "name",
		Type:        "file",
		Path:        "foo.zip",
		Description: "something",
		Origin:      "store",
		Revision:    5,
		Fingerprint: fp.Bytes(),
		Size:        4,
	}
	dev := params.Resource{
		Name:        "name2",
		Type:        "file",
		Path:        "bar.zip",
		Description: "something",
		Origin:      "store",
		Revision:    7,
		Fingerprint: fp.Bytes(),
		Size:        4,
	}
	dev2 := params.Resource{
		Name:        "name3",
		Type:        "file",
		Path:        "bar.zip",
		Description: "something",
		Origin:      "store",
		Revision:    8,
		Fingerprint: fp.Bytes(),
		Size:        4,
	}

	s.wrapper.ReturnListResourcesStable = []resourceResult{oneResourceResult(stable), resourceResult{err: params.ErrNotFound}}
	s.wrapper.ReturnListResourcesDev = []resourceResult{oneResourceResult(dev), oneResourceResult(dev2)}

	client, err := newCachingClient(s.cache, nil, s.wrapper.makeWrapper)
	c.Assert(err, jc.ErrorIsNil)

	foo := charm.MustParseURL("cs:quantal/foo-1")
	bar := charm.MustParseURL("cs:quantal/bar-1")
	baz := charm.MustParseURL("cs:quantal/baz-1")

	ret, err := client.ListResources([]CharmID{{
		URL:     foo,
		Channel: params.StableChannel,
	}, {
		URL:     bar,
		Channel: params.DevelopmentChannel,
	}, {
		URL:     baz,
		Channel: params.DevelopmentChannel,
	}})
	c.Assert(err, jc.ErrorIsNil)

	stableOut, err := params.API2Resource(stable)
	c.Assert(err, jc.ErrorIsNil)

	devOut, err := params.API2Resource(dev)
	c.Assert(err, jc.ErrorIsNil)

	dev2Out, err := params.API2Resource(dev2)
	c.Assert(err, jc.ErrorIsNil)

	c.Assert(ret, gc.DeepEquals, [][]resource.Resource{
		{stableOut},
		{devOut},
		{dev2Out},
	})
	s.wrapper.stableStub.CheckCall(c, 0, "ListResources", params.StableChannel, foo)
	s.wrapper.devStub.CheckCall(c, 0, "ListResources", params.DevelopmentChannel, bar)
	s.wrapper.devStub.CheckCall(c, 1, "ListResources", params.DevelopmentChannel, baz)
}
Example #12
0
func (s *LatestCharmInfoSuite) TestSuccess(c *gc.C) {
	spam := charm.MustParseURL("cs:quantal/spam-17")
	eggs := charm.MustParseURL("cs:quantal/eggs-2")
	ham := charm.MustParseURL("cs:quantal/ham-1")
	charms := []CharmID{
		{URL: spam, Channel: "stable"},
		{URL: eggs, Channel: "stable"},
		{URL: ham, Channel: "stable"},
	}
	notFound := errors.New("not found")
	s.lowLevel.ReturnLatestStable = [][]params.CharmRevision{{{
		Revision: 17,
	}}, {{
		Revision: 3,
	}}, {{
		Err: notFound,
	}}}

	fakeRes := fakeParamsResource("foo", nil)

	s.lowLevel.ReturnListResourcesStable = []resourceResult{
		oneResourceResult(fakeRes),
		resourceResult{err: params.ErrNotFound},
		resourceResult{err: params.ErrUnauthorized},
	}

	client, err := newCachingClient(s.cache, nil, s.lowLevel.makeWrapper)
	c.Assert(err, jc.ErrorIsNil)

	metadata := map[string]string{
		"environment_uuid": "foouuid",
		"cloud":            "foocloud",
		"cloud_region":     "fooregion",
		"provider":         "fooprovider",
	}
	results, err := LatestCharmInfo(client, charms, metadata)
	c.Assert(err, jc.ErrorIsNil)

	header := []string{"environment_uuid=foouuid", "cloud=foocloud", "cloud_region=fooregion", "provider=fooprovider", "controller_version=" + version.Current.String()}
	s.lowLevel.stableStub.CheckCall(c, 0, "Latest", params.StableChannel, []*charm.URL{spam}, map[string][]string{"Juju-Metadata": header})
	s.lowLevel.stableStub.CheckCall(c, 1, "Latest", params.StableChannel, []*charm.URL{eggs}, map[string][]string{"Juju-Metadata": header})
	s.lowLevel.stableStub.CheckCall(c, 2, "Latest", params.StableChannel, []*charm.URL{ham}, map[string][]string{"Juju-Metadata": header})
	s.lowLevel.stableStub.CheckCall(c, 3, "ListResources", params.StableChannel, spam)
	s.lowLevel.stableStub.CheckCall(c, 4, "ListResources", params.StableChannel, eggs)
	s.lowLevel.stableStub.CheckCall(c, 5, "ListResources", params.StableChannel, ham)

	expectedRes, err := params.API2Resource(fakeRes)
	c.Assert(err, jc.ErrorIsNil)

	timestamp := results[0].Timestamp
	results[2].Error = errors.Cause(results[2].Error)
	expected := []CharmInfoResult{{
		CharmInfo: CharmInfo{
			OriginalURL:    charm.MustParseURL("cs:quantal/spam-17"),
			Timestamp:      timestamp,
			LatestRevision: 17,
			LatestResources: []charmresource.Resource{
				expectedRes,
			},
		},
	}, {
		CharmInfo: CharmInfo{
			OriginalURL:    charm.MustParseURL("cs:quantal/eggs-2"),
			Timestamp:      timestamp,
			LatestRevision: 3,
		},
	}, {
		CharmInfo: CharmInfo{
			OriginalURL: charm.MustParseURL("cs:quantal/ham-1"),
			Timestamp:   timestamp,
		},
		Error: notFound,
	}}
	sort.Sort(byURL(results))
	sort.Sort(byURL(expected))
	c.Check(results, jc.DeepEquals, expected)
}