Example #1
0
func (s *GitDeployerSuite) TestInstall(c *gc.C) {
	// Prepare.
	info := s.bundles.AddCustomBundle(c, corecharm.MustParseURL("cs:s/c-1"), func(path string) {
		err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644)
		c.Assert(err, gc.IsNil)
	})
	err := s.deployer.Stage(info, nil)
	c.Assert(err, gc.IsNil)
	checkCleanup(c, s.deployer)

	// Install.
	err = s.deployer.Deploy()
	c.Assert(err, gc.IsNil)
	checkCleanup(c, s.deployer)

	// Check content.
	data, err := ioutil.ReadFile(filepath.Join(s.targetPath, "some-file"))
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), gc.Equals, "hello")

	target := charm.NewGitDir(s.targetPath)
	url, err := target.ReadCharmURL()
	c.Assert(err, gc.IsNil)
	c.Assert(url, gc.DeepEquals, corecharm.MustParseURL("cs:s/c-1"))
	lines, err := target.Log()
	c.Assert(err, gc.IsNil)
	c.Assert(lines, gc.HasLen, 2)
	c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Deployed charm "cs:s/c-1"\.`)
	c.Assert(lines[1], gc.Matches, `[0-9a-f]{7} Imported charm "cs:s/c-1"\.`)
}
Example #2
0
func (s *StoreSuite) TestLockUpdatesExpires(c *gc.C) {
	urlA := charm.MustParseURL("cs:oneiric/wordpress-a")
	urlB := charm.MustParseURL("cs:oneiric/wordpress-b")
	urls := []*charm.URL{urlA, urlB}

	// Initiate an update of B only to force a partial conflict.
	lock1, err := s.store.LockUpdates(urls[1:])
	c.Assert(err, gc.IsNil)

	// Hack time to force an expiration.
	locks := s.Session.DB("juju").C("locks")
	selector := bson.M{"_id": urlB.String()}
	update := bson.M{"time": bson.Now().Add(-store.UpdateTimeout - 10e9)}
	err = locks.Update(selector, update)
	c.Check(err, gc.IsNil)

	// Works due to expiration of previous lock.
	lock2, err := s.store.LockUpdates(urls)
	c.Assert(err, gc.IsNil)
	defer lock2.Unlock()

	// The expired lock was forcefully killed. Unlocking it must
	// not interfere with lock2 which is still alive.
	lock1.Unlock()

	// The above statement was a NOOP and lock2 is still in effect,
	// so attempting another lock must necessarily fail.
	lock3, err := s.store.LockUpdates(urls)
	c.Check(err, gc.Equals, store.ErrUpdateConflict)
	c.Check(lock3, gc.IsNil)
}
Example #3
0
func (s *StoreSuite) TestRedundantUpdate(c *gc.C) {
	urlA := charm.MustParseURL("cs:oneiric/wordpress-a")
	urlB := charm.MustParseURL("cs:oneiric/wordpress-b")
	urls := []*charm.URL{urlA, urlB}

	pub, err := s.store.CharmPublisher(urls, "digest-0")
	c.Assert(err, gc.IsNil)
	c.Assert(pub.Revision(), gc.Equals, 0)
	err = pub.Publish(&FakeCharmDir{})
	c.Assert(err, gc.IsNil)

	// All charms are already on digest-0.
	pub, err = s.store.CharmPublisher(urls, "digest-0")
	c.Assert(err, gc.ErrorMatches, "charm is up-to-date")
	c.Assert(err, gc.Equals, store.ErrRedundantUpdate)
	c.Assert(pub, gc.IsNil)

	// Now add a second revision just for wordpress-b.
	pub, err = s.store.CharmPublisher(urls[1:], "digest-1")
	c.Assert(err, gc.IsNil)
	c.Assert(pub.Revision(), gc.Equals, 1)
	err = pub.Publish(&FakeCharmDir{})
	c.Assert(err, gc.IsNil)

	// Same digest bumps revision because one of them was old.
	pub, err = s.store.CharmPublisher(urls, "digest-1")
	c.Assert(err, gc.IsNil)
	c.Assert(pub.Revision(), gc.Equals, 2)
	err = pub.Publish(&FakeCharmDir{})
	c.Assert(err, gc.IsNil)
}
Example #4
0
func (s *StoreSuite) TestCharmPublishError(c *gc.C) {
	url := charm.MustParseURL("cs:oneiric/wordpress")
	urls := []*charm.URL{url}

	// Publish one successfully to bump the revision so we can
	// make sure it is being correctly set below.
	pub, err := s.store.CharmPublisher(urls, "one-digest")
	c.Assert(err, gc.IsNil)
	c.Assert(pub.Revision(), gc.Equals, 0)
	err = pub.Publish(&FakeCharmDir{})
	c.Assert(err, gc.IsNil)

	pub, err = s.store.CharmPublisher(urls, "another-digest")
	c.Assert(err, gc.IsNil)
	c.Assert(pub.Revision(), gc.Equals, 1)
	err = pub.Publish(&FakeCharmDir{error: "beforeWrite"})
	c.Assert(err, gc.ErrorMatches, "beforeWrite")

	pub, err = s.store.CharmPublisher(urls, "another-digest")
	c.Assert(err, gc.IsNil)
	c.Assert(pub.Revision(), gc.Equals, 1)
	err = pub.Publish(&FakeCharmDir{error: "afterWrite"})
	c.Assert(err, gc.ErrorMatches, "afterWrite")

	// Still at the original charm revision that succeeded first.
	info, err := s.store.CharmInfo(url)
	c.Assert(err, gc.IsNil)
	c.Assert(info.Revision(), gc.Equals, 0)
	c.Assert(info.Digest(), gc.Equals, "one-digest")
}
Example #5
0
func (s *FilterSuite) TestCharmErrorEvents(c *gc.C) {
	f, err := newFilter(s.uniter, s.unit.Tag())
	c.Assert(err, gc.IsNil)
	defer f.Stop() // no AssertStop, we test for an error below

	assertNoChange := func() {
		s.BackingState.StartSync()
		select {
		case <-f.ConfigEvents():
			c.Fatalf("unexpected config event")
		case <-time.After(coretesting.ShortWait):
		}
	}

	// Check setting an invalid charm URL does not send events.
	err = f.SetCharm(charm.MustParseURL("cs:missing/one-1"))
	c.Assert(err, gc.Equals, tomb.ErrDying)
	assertNoChange()
	s.assertFilterDies(c, f)

	// Filter died after the error, so restart it.
	f, err = newFilter(s.uniter, s.unit.Tag())
	c.Assert(err, gc.IsNil)
	defer f.Stop() // no AssertStop, we test for an error below

	// Check with a nil charm URL, again no changes.
	err = f.SetCharm(nil)
	c.Assert(err, gc.Equals, tomb.ErrDying)
	assertNoChange()
	s.assertFilterDies(c, f)
}
Example #6
0
func (s *StoreSuite) TestConflictingUpdate(c *gc.C) {
	// This test checks that if for whatever reason the locking
	// safety-net fails, adding two charms in parallel still
	// results in a sane outcome.
	url := charm.MustParseURL("cs:oneiric/wordpress")
	urls := []*charm.URL{url}

	pub1, err := s.store.CharmPublisher(urls, "some-digest")
	c.Assert(err, gc.IsNil)
	c.Assert(pub1.Revision(), gc.Equals, 0)

	pub2, err := s.store.CharmPublisher(urls, "some-digest")
	c.Assert(err, gc.IsNil)
	c.Assert(pub2.Revision(), gc.Equals, 0)

	// The first publishing attempt should work.
	err = pub2.Publish(&FakeCharmDir{})
	c.Assert(err, gc.IsNil)

	// Attempting to finish the second attempt should break,
	// since it lost the race and the given revision is already
	// in place.
	err = pub1.Publish(&FakeCharmDir{})
	c.Assert(err, gc.Equals, store.ErrUpdateConflict)
}
Example #7
0
func (s *SSHSuite) TestSSHCommand(c *gc.C) {
	m := s.makeMachines(3, c, true)
	ch := coretesting.Charms.Dir("dummy")
	curl := charm.MustParseURL(
		fmt.Sprintf("local:quantal/%s-%d", ch.Meta().Name, ch.Revision()),
	)
	bundleURL, err := url.Parse("http://bundles.testing.invalid/dummy-1")
	c.Assert(err, gc.IsNil)
	dummy, err := s.State.AddCharm(ch, curl, bundleURL, "dummy-1-sha256")
	c.Assert(err, gc.IsNil)
	srv := s.AddTestingService(c, "mysql", dummy)
	s.addUnit(srv, m[0], c)

	srv = s.AddTestingService(c, "mongodb", dummy)
	s.addUnit(srv, m[1], c)
	s.addUnit(srv, m[2], c)

	for i, t := range sshTests {
		c.Logf("test %d: %s -> %s\n", i, t.about, t.args)
		ctx := coretesting.Context(c)
		jujucmd := cmd.NewSuperCommand(cmd.SuperCommandParams{})
		jujucmd.Register(envcmd.Wrap(&SSHCommand{}))

		code := cmd.Main(jujucmd, ctx, t.args)
		c.Check(code, gc.Equals, 0)
		c.Check(ctx.Stderr.(*bytes.Buffer).String(), gc.Equals, "")
		c.Check(ctx.Stdout.(*bytes.Buffer).String(), gc.Equals, t.result)
	}
}
Example #8
0
func (s *DeploySuite) TestCharmDir(c *gc.C) {
	coretesting.Charms.ClonedDirPath(s.SeriesPath, "dummy")
	err := runDeploy(c, "local:dummy")
	c.Assert(err, gc.IsNil)
	curl := charm.MustParseURL("local:precise/dummy-1")
	s.AssertService(c, "dummy", curl, 1, 0)
}
Example #9
0
func (s *DeploySuite) TestNumUnits(c *gc.C) {
	coretesting.Charms.BundlePath(s.SeriesPath, "dummy")
	err := runDeploy(c, "local:dummy", "-n", "13")
	c.Assert(err, gc.IsNil)
	curl := charm.MustParseURL("local:precise/dummy-1")
	s.AssertService(c, "dummy", curl, 13, 0)
}
Example #10
0
func (s *DeploySuite) TestSubordinateCharm(c *gc.C) {
	coretesting.Charms.BundlePath(s.SeriesPath, "logging")
	err := runDeploy(c, "local:logging")
	c.Assert(err, gc.IsNil)
	curl := charm.MustParseURL("local:precise/logging-1")
	s.AssertService(c, "logging", curl, 0, 0)
}
Example #11
0
func addCharm(c *gc.C, st *State, series string, ch charm.Charm) *Charm {
	ident := fmt.Sprintf("%s-%s-%d", series, ch.Meta().Name, ch.Revision())
	curl := charm.MustParseURL("local:" + series + "/" + ident)
	bundleURL, err := url.Parse("http://bundles.testing.invalid/" + ident)
	c.Assert(err, gc.IsNil)
	sch, err := st.AddCharm(ch, curl, bundleURL, ident+"-sha256")
	c.Assert(err, gc.IsNil)
	return sch
}
Example #12
0
func (s *GitDeployerSuite) TestUpgrade(c *gc.C) {
	// Install.
	info1 := s.bundles.AddCustomBundle(c, corecharm.MustParseURL("cs:s/c-1"), func(path string) {
		err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("hello"), 0644)
		c.Assert(err, gc.IsNil)
		err = os.Symlink("./some-file", filepath.Join(path, "a-symlink"))
		c.Assert(err, gc.IsNil)
	})
	err := s.deployer.Stage(info1, nil)
	c.Assert(err, gc.IsNil)
	err = s.deployer.Deploy()
	c.Assert(err, gc.IsNil)

	// Upgrade.
	info2 := s.bundles.AddCustomBundle(c, corecharm.MustParseURL("cs:s/c-2"), func(path string) {
		err := ioutil.WriteFile(filepath.Join(path, "some-file"), []byte("goodbye"), 0644)
		c.Assert(err, gc.IsNil)
		err = ioutil.WriteFile(filepath.Join(path, "a-symlink"), []byte("not any more!"), 0644)
		c.Assert(err, gc.IsNil)
	})
	err = s.deployer.Stage(info2, nil)
	c.Assert(err, gc.IsNil)
	checkCleanup(c, s.deployer)
	err = s.deployer.Deploy()
	c.Assert(err, gc.IsNil)
	checkCleanup(c, s.deployer)

	// Check content.
	data, err := ioutil.ReadFile(filepath.Join(s.targetPath, "some-file"))
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), gc.Equals, "goodbye")
	data, err = ioutil.ReadFile(filepath.Join(s.targetPath, "a-symlink"))
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), gc.Equals, "not any more!")

	target := charm.NewGitDir(s.targetPath)
	url, err := target.ReadCharmURL()
	c.Assert(err, gc.IsNil)
	c.Assert(url, gc.DeepEquals, corecharm.MustParseURL("cs:s/c-2"))
	lines, err := target.Log()
	c.Assert(err, gc.IsNil)
	c.Assert(lines, gc.HasLen, 5)
	c.Assert(lines[0], gc.Matches, `[0-9a-f]{7} Upgraded charm to "cs:s/c-2".`)
}
Example #13
0
func (s *StoreSuite) TestRevisioning(c *gc.C) {
	urlA := charm.MustParseURL("cs:oneiric/wordpress-a")
	urlB := charm.MustParseURL("cs:oneiric/wordpress-b")
	urls := []*charm.URL{urlA, urlB}

	tests := []struct {
		urls []*charm.URL
		data string
	}{
		{urls[0:], "charm-revision-0"},
		{urls[1:], "charm-revision-1"},
		{urls[0:], "charm-revision-2"},
	}

	for i, t := range tests {
		pub, err := s.store.CharmPublisher(t.urls, fmt.Sprintf("digest-%d", i))
		c.Assert(err, gc.IsNil)
		c.Assert(pub.Revision(), gc.Equals, i)

		err = pub.Publish(&FakeCharmDir{})
		c.Assert(err, gc.IsNil)
	}

	for i, t := range tests {
		for _, url := range t.urls {
			url = url.WithRevision(i)
			info, rc, err := s.store.OpenCharm(url)
			c.Assert(err, gc.IsNil)
			data, err := ioutil.ReadAll(rc)
			cerr := rc.Close()
			c.Assert(info.Revision(), gc.Equals, i)
			c.Assert(url.Revision, gc.Equals, i) // Untouched.
			c.Assert(cerr, gc.IsNil)
			c.Assert(string(data), gc.Equals, string(t.data))
			c.Assert(err, gc.IsNil)
		}
	}

	info, rc, err := s.store.OpenCharm(urlA.WithRevision(1))
	c.Assert(err, gc.Equals, store.ErrNotFound)
	c.Assert(info, gc.IsNil)
	c.Assert(rc, gc.IsNil)
}
Example #14
0
func (s *DeploySuite) TestConstraints(c *gc.C) {
	coretesting.Charms.BundlePath(s.SeriesPath, "dummy")
	err := runDeploy(c, "local:dummy", "--constraints", "mem=2G cpu-cores=2")
	c.Assert(err, gc.IsNil)
	curl := charm.MustParseURL("local:precise/dummy-1")
	service, _ := s.AssertService(c, "dummy", curl, 1, 0)
	cons, err := service.Constraints()
	c.Assert(err, gc.IsNil)
	c.Assert(cons, gc.DeepEquals, constraints.MustParse("mem=2G cpu-cores=2"))
}
Example #15
0
func (s *StoreSuite) prepareServer(c *gc.C) (*store.Server, *charm.URL) {
	curl := charm.MustParseURL("cs:precise/wordpress")
	pub, err := s.store.CharmPublisher([]*charm.URL{curl}, "some-digest")
	c.Assert(err, gc.IsNil)
	err = pub.Publish(&FakeCharmDir{})
	c.Assert(err, gc.IsNil)

	server, err := store.NewServer(s.store)
	c.Assert(err, gc.IsNil)
	return server, curl
}
Example #16
0
func (s *DeploySuite) TestNetworks(c *gc.C) {
	coretesting.Charms.BundlePath(s.SeriesPath, "dummy")
	err := runDeploy(c, "local:dummy", "--networks", ", net1, net2 , ")
	c.Assert(err, gc.IsNil)
	curl := charm.MustParseURL("local:precise/dummy-1")
	service, _ := s.AssertService(c, "dummy", curl, 1, 0)
	includeNetworks, excludeNetworks, err := service.Networks()
	c.Assert(err, gc.IsNil)
	c.Assert(includeNetworks, gc.DeepEquals, []string{"net1", "net2"})
	c.Assert(excludeNetworks, gc.HasLen, 0)
}
Example #17
0
func (s *StoreSuite) TestLockUpdates(c *gc.C) {
	urlA := charm.MustParseURL("cs:oneiric/wordpress-a")
	urlB := charm.MustParseURL("cs:oneiric/wordpress-b")
	urls := []*charm.URL{urlA, urlB}

	// Lock update of just B to force a partial conflict.
	lock1, err := s.store.LockUpdates(urls[1:])
	c.Assert(err, gc.IsNil)

	// Partially conflicts with locked update above.
	lock2, err := s.store.LockUpdates(urls)
	c.Check(err, gc.Equals, store.ErrUpdateConflict)
	c.Check(lock2, gc.IsNil)

	lock1.Unlock()

	// Trying again should work since lock1 was released.
	lock3, err := s.store.LockUpdates(urls)
	c.Assert(err, gc.IsNil)
	lock3.Unlock()
}
Example #18
0
func (s *StoreSuite) TestCharmPublisher(c *gc.C) {
	urlA := charm.MustParseURL("cs:oneiric/wordpress-a")
	urlB := charm.MustParseURL("cs:oneiric/wordpress-b")
	urls := []*charm.URL{urlA, urlB}

	pub, err := s.store.CharmPublisher(urls, "some-digest")
	c.Assert(err, gc.IsNil)
	c.Assert(pub.Revision(), gc.Equals, 0)

	err = pub.Publish(testing.Charms.ClonedDir(c.MkDir(), "dummy"))
	c.Assert(err, gc.IsNil)

	for _, url := range urls {
		info, rc, err := s.store.OpenCharm(url)
		c.Assert(err, gc.IsNil)
		c.Assert(info.Revision(), gc.Equals, 0)
		c.Assert(info.Digest(), gc.Equals, "some-digest")
		data, err := ioutil.ReadAll(rc)
		c.Check(err, gc.IsNil)
		err = rc.Close()
		c.Assert(err, gc.IsNil)
		bundle, err := charm.ReadBundleBytes(data)
		c.Assert(err, gc.IsNil)

		// The same information must be available by reading the
		// full charm data...
		c.Assert(bundle.Meta().Name, gc.Equals, "dummy")
		c.Assert(bundle.Config().Options["title"].Default, gc.Equals, "My Title")

		// ... and the queriable details.
		c.Assert(info.Meta().Name, gc.Equals, "dummy")
		c.Assert(info.Config().Options["title"].Default, gc.Equals, "My Title")

		info2, err := s.store.CharmInfo(url)
		c.Assert(err, gc.IsNil)
		c.Assert(info2, gc.DeepEquals, info)
	}
}
Example #19
0
func (s *StoreSuite) TestDeleteCharm(c *gc.C) {
	url := charm.MustParseURL("cs:oneiric/wordpress")
	for i := 0; i < 4; i++ {
		pub, err := s.store.CharmPublisher([]*charm.URL{url},
			fmt.Sprintf("some-digest-%d", i))
		c.Assert(err, gc.IsNil)
		c.Assert(pub.Revision(), gc.Equals, i)

		err = pub.Publish(testing.Charms.ClonedDir(c.MkDir(), "dummy"))
		c.Assert(err, gc.IsNil)
	}

	// Verify charms were published
	info, rc, err := s.store.OpenCharm(url)
	c.Assert(err, gc.IsNil)
	err = rc.Close()
	c.Assert(err, gc.IsNil)
	c.Assert(info.Revision(), gc.Equals, 3)

	// Delete an arbitrary middle revision
	url1 := url.WithRevision(1)
	infos, err := s.store.DeleteCharm(url1)
	c.Assert(err, gc.IsNil)
	c.Assert(len(infos), gc.Equals, 1)

	// Verify still published
	info, rc, err = s.store.OpenCharm(url)
	c.Assert(err, gc.IsNil)
	err = rc.Close()
	c.Assert(err, gc.IsNil)
	c.Assert(info.Revision(), gc.Equals, 3)

	// Delete all revisions
	expectedRevs := map[int]bool{0: true, 2: true, 3: true}
	infos, err = s.store.DeleteCharm(url)
	c.Assert(err, gc.IsNil)
	c.Assert(len(infos), gc.Equals, 3)
	for _, deleted := range infos {
		// We deleted the charm we expected to
		c.Assert(info.Meta().Name, gc.Equals, deleted.Meta().Name)
		_, has := expectedRevs[deleted.Revision()]
		c.Assert(has, gc.Equals, true)
		delete(expectedRevs, deleted.Revision())
	}
	c.Assert(len(expectedRevs), gc.Equals, 0)

	// The charm is all gone
	_, _, err = s.store.OpenCharm(url)
	c.Assert(err, gc.Not(gc.IsNil))
}
Example #20
0
func (s *StoreSuite) TestLogCharmEventWithRevisionedURL(c *gc.C) {
	url := charm.MustParseURL("cs:oneiric/wordpress-0")
	event := &store.CharmEvent{
		Kind:   store.EventPublishError,
		Digest: "some-digest",
		URLs:   []*charm.URL{url},
	}
	err := s.store.LogCharmEvent(event)
	c.Assert(err, gc.ErrorMatches, "LogCharmEvent: got charm URL with revision: cs:oneiric/wordpress-0")

	// This may work in the future, but not now.
	event, err = s.store.CharmEvent(url, "some-digest")
	c.Assert(err, gc.ErrorMatches, "CharmEvent: got charm URL with revision: cs:oneiric/wordpress-0")
	c.Assert(event, gc.IsNil)
}
Example #21
0
func (s *MockStore) serveEvent(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	response := map[string]*charm.EventResponse{}
	for _, url := range r.Form["charms"] {
		digest := ""
		if i := strings.Index(url, "@"); i >= 0 {
			digest = url[i+1:]
			url = url[:i]
		}
		er := &charm.EventResponse{}
		response[url] = er
		if digest != "" && digest != "the-digest" {
			er.Kind = "not-found"
			er.Errors = []string{"entry not found"}
			continue
		}
		charmURL := charm.MustParseURL(url)
		switch charmURL.Name {
		case "borken":
			er.Kind = "publish-error"
			er.Errors = append(er.Errors, "badness")
		case "unwise":
			er.Warnings = append(er.Warnings, "foolishness")
			fallthrough
		default:
			if rev, ok := s.charms[charmURL.WithRevision(-1).String()]; ok {
				er.Kind = "published"
				er.Revision = rev
				er.Digest = "the-digest"
			} else {
				er.Kind = "not-found"
				er.Errors = []string{"entry not found"}
			}
		}
	}
	data, err := json.Marshal(response)
	if err != nil {
		panic(err)
	}
	w.Header().Set("Content-Type", "application/json")
	_, err = w.Write(data)
	if err != nil {
		panic(err)
	}
}
Example #22
0
func (s *StoreSuite) TestCharmBundleData(c *gc.C) {
	url := charm.MustParseURL("cs:oneiric/wordpress")
	urls := []*charm.URL{url}

	pub, err := s.store.CharmPublisher(urls, "key")
	c.Assert(err, gc.IsNil)
	c.Assert(pub.Revision(), gc.Equals, 0)

	err = pub.Publish(&FakeCharmDir{})
	c.Assert(err, gc.IsNil)

	info, rc, err := s.store.OpenCharm(url)
	c.Assert(err, gc.IsNil)
	c.Check(info.BundleSha256(), gc.Equals, fakeRevZeroSha)
	c.Check(info.BundleSize(), gc.Equals, int64(len("charm-revision-0")))
	err = rc.Close()
	c.Check(err, gc.IsNil)
}
Example #23
0
func (s *UnexposeSuite) TestUnexpose(c *gc.C) {
	testing.Charms.BundlePath(s.SeriesPath, "dummy")
	err := runDeploy(c, "local:dummy", "some-service-name")
	c.Assert(err, gc.IsNil)
	curl := charm.MustParseURL("local:precise/dummy-1")
	s.AssertService(c, "some-service-name", curl, 1, 0)

	err = runExpose(c, "some-service-name")
	c.Assert(err, gc.IsNil)
	s.assertExposed(c, "some-service-name", true)

	err = runUnexpose(c, "some-service-name")
	c.Assert(err, gc.IsNil)
	s.assertExposed(c, "some-service-name", false)

	err = runUnexpose(c, "nonexistent-service")
	c.Assert(err, gc.ErrorMatches, `service "nonexistent-service" not found`)
}
Example #24
0
func (s *StoreSuite) TestSeriesSolver(c *gc.C) {
	for _, t := range seriesSolverCharms {
		url := charm.MustParseURL(fmt.Sprintf("cs:%s/%s", t.series, t.name))
		urls := []*charm.URL{url}

		pub, err := s.store.CharmPublisher(urls, fmt.Sprintf("some-%s-%s-digest", t.series, t.name))
		c.Assert(err, gc.IsNil)
		c.Assert(pub.Revision(), gc.Equals, 0)

		err = pub.Publish(&FakeCharmDir{})
		c.Assert(err, gc.IsNil)
	}

	// LTS, then non-LTS, reverse alphabetical order
	ref, _, err := charm.ParseReference("cs:wordpress")
	c.Assert(err, gc.IsNil)
	series, err := s.store.Series(ref)
	c.Assert(err, gc.IsNil)
	c.Assert(series, gc.HasLen, 5)
	c.Check(series[0], gc.Equals, "trusty")
	c.Check(series[1], gc.Equals, "precise")
	c.Check(series[2], gc.Equals, "volumetric")
	c.Check(series[3], gc.Equals, "quantal")
	c.Check(series[4], gc.Equals, "oneiric")

	// Ensure that the full charm name matches, not just prefix
	ref, _, err = charm.ParseReference("cs:mysql")
	c.Assert(err, gc.IsNil)
	series, err = s.store.Series(ref)
	c.Assert(err, gc.IsNil)
	c.Assert(series, gc.HasLen, 1)
	c.Check(series[0], gc.Equals, "precise")

	// No LTS, reverse alphabetical order
	ref, _, err = charm.ParseReference("cs:zebra")
	c.Assert(err, gc.IsNil)
	series, err = s.store.Series(ref)
	c.Assert(err, gc.IsNil)
	c.Assert(series, gc.HasLen, 2)
	c.Check(series[0], gc.Equals, "zef")
	c.Check(series[1], gc.Equals, "def")
}
Example #25
0
func (s *charmVersionSuite) TestUpdateRevisions(c *gc.C) {
	s.AddMachine(c, "0", state.JobManageEnviron)
	s.SetupScenario(c)

	curl := charm.MustParseURL("cs:quantal/mysql")
	_, err := s.State.LatestPlaceholderCharm(curl)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)

	curl = charm.MustParseURL("cs:quantal/wordpress")
	_, err = s.State.LatestPlaceholderCharm(curl)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)

	result, err := s.charmrevisionupdater.UpdateLatestRevisions()
	c.Assert(err, gc.IsNil)
	c.Assert(result.Error, gc.IsNil)

	curl = charm.MustParseURL("cs:quantal/mysql")
	pending, err := s.State.LatestPlaceholderCharm(curl)
	c.Assert(err, gc.IsNil)
	c.Assert(pending.String(), gc.Equals, "cs:quantal/mysql-23")

	// Latest wordpress is already deployed, so no pending charm.
	curl = charm.MustParseURL("cs:quantal/wordpress")
	_, err = s.State.LatestPlaceholderCharm(curl)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)

	// Varnish has an error when updating, so no pending charm.
	curl = charm.MustParseURL("cs:quantal/varnish")
	_, err = s.State.LatestPlaceholderCharm(curl)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)

	// Update mysql version and run update again.
	svc, err := s.State.Service("mysql")
	c.Assert(err, gc.IsNil)
	ch := s.AddCharmWithRevision(c, "mysql", 23)
	err = svc.SetCharm(ch, true)
	c.Assert(err, gc.IsNil)

	result, err = s.charmrevisionupdater.UpdateLatestRevisions()
	c.Assert(err, gc.IsNil)
	c.Assert(result.Error, gc.IsNil)

	// Latest mysql is now deployed, so no pending charm.
	curl = charm.MustParseURL("cs:quantal/mysql")
	_, err = s.State.LatestPlaceholderCharm(curl)
	c.Assert(err, jc.Satisfies, errors.IsNotFound)
}
Example #26
0
func (s *DeleteCharmSuite) TestRun(c *gc.C) {
	// Derive config file from test mongo port
	confDir := c.MkDir()
	f, err := os.Create(path.Join(confDir, "charmd.conf"))
	c.Assert(err, gc.IsNil)
	configPath := f.Name()
	{
		defer f.Close()
		fmt.Fprintf(f, "mongo-url: %s\n", testing.MgoServer.Addr())
	}
	// Delete charm that does not exist, not found error.
	config := &DeleteCharmCommand{}
	out, err := testing.RunCommand(c, config, "--config", configPath, "--url", "cs:unreleased/foo")
	fmt.Println(out)
	c.Assert(err, gc.NotNil)
	// Publish that charm now
	url := charm.MustParseURL("cs:unreleased/foo")
	{
		s, err := store.Open(testing.MgoServer.Addr())
		defer s.Close()
		c.Assert(err, gc.IsNil)
		pub, err := s.CharmPublisher([]*charm.URL{url}, "such-digest-much-unique")
		c.Assert(err, gc.IsNil)
		err = pub.Publish(testing.Charms.ClonedDir(c.MkDir(), "dummy"))
		c.Assert(err, gc.IsNil)
	}
	// Delete charm, should now succeed
	_, err = testing.RunCommand(c, config, "--config", configPath, "--url", "cs:unreleased/foo")
	c.Assert(err, gc.IsNil)
	c.Assert(config.Config, gc.NotNil)
	// Confirm that the charm is gone
	{
		s, err := store.Open(testing.MgoServer.Addr())
		defer s.Close()
		c.Assert(err, gc.IsNil)
		_, err = s.CharmInfo(url)
		c.Assert(err, gc.NotNil)
	}
}
Example #27
0
func (s *MockStore) serveCharm(w http.ResponseWriter, r *http.Request) {
	charmURL := charm.MustParseURL("cs:" + r.URL.Path[len("/charm/"):])

	r.ParseForm()
	if r.Form.Get("stats") == "0" {
		s.DownloadsNoStats = append(s.DownloadsNoStats, charmURL)
	} else {
		s.Downloads = append(s.Downloads, charmURL)
	}

	if auth := r.Header.Get("Authorization"); auth != "" {
		s.Authorizations = append(s.Authorizations, auth)
	}

	w.Header().Set("Connection", "close")
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Header().Set("Content-Length", strconv.Itoa(len(s.bundleBytes)))
	_, err := w.Write(s.bundleBytes)
	if err != nil {
		panic(err)
	}
}
Example #28
0
func (s *StoreSuite) TestMysqlSeriesSolver(c *gc.C) {
	for _, t := range mysqlSeriesCharms {
		var urls []*charm.URL
		for _, url := range t.urls {
			urls = append(urls, charm.MustParseURL(url))
		}

		pub, err := s.store.CharmPublisher(urls, t.fakeDigest)
		c.Assert(err, gc.IsNil)
		c.Assert(pub.Revision(), gc.Equals, 0)

		err = pub.Publish(&FakeCharmDir{})
		c.Assert(err, gc.IsNil)
	}

	ref, _, err := charm.ParseReference("cs:mysql")
	c.Assert(err, gc.IsNil)
	series, err := s.store.Series(ref)
	c.Assert(err, gc.IsNil)
	c.Assert(series, gc.HasLen, 2)
	c.Check(series[0], gc.Equals, "precise")
	c.Check(series[1], gc.Equals, "oneiric")
}
Example #29
0
func (s *MachineWithCharmsSuite) TestManageEnvironRunsCharmRevisionUpdater(c *gc.C) {
	m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron)

	s.SetupScenario(c)

	a := s.newAgent(c, m)
	go func() {
		c.Check(a.Run(nil), gc.IsNil)
	}()
	defer func() { c.Check(a.Stop(), gc.IsNil) }()

	checkRevision := func() bool {
		curl := charm.MustParseURL("cs:quantal/mysql")
		placeholder, err := s.State.LatestPlaceholderCharm(curl)
		return err == nil && placeholder.String() == curl.WithRevision(23).String()
	}
	success := false
	for attempt := coretesting.LongAttempt.Start(); attempt.Next(); {
		if success = checkRevision(); success {
			break
		}
	}
	c.Assert(success, gc.Equals, true)
}
Example #30
0
func (s *StoreSuite) TestServerCharmEvent(c *gc.C) {
	server, _ := s.prepareServer(c)
	req, err := http.NewRequest("GET", "/charm-event", nil)
	c.Assert(err, gc.IsNil)

	url1 := charm.MustParseURL("cs:oneiric/wordpress")
	url2 := charm.MustParseURL("cs:oneiric/mysql")
	urls := []*charm.URL{url1, url2}

	event1 := &store.CharmEvent{
		Kind:     store.EventPublished,
		Revision: 42,
		Digest:   "revKey1",
		URLs:     urls,
		Warnings: []string{"A warning."},
		Time:     time.Unix(1, 0),
	}
	event2 := &store.CharmEvent{
		Kind:     store.EventPublished,
		Revision: 43,
		Digest:   "revKey2",
		URLs:     urls,
		Time:     time.Unix(2, 0),
	}
	event3 := &store.CharmEvent{
		Kind:   store.EventPublishError,
		Digest: "revKey3",
		Errors: []string{"An error."},
		URLs:   urls[:1],
		Time:   time.Unix(3, 0),
	}

	for _, event := range []*store.CharmEvent{event1, event2, event3} {
		err := s.store.LogCharmEvent(event)
		c.Assert(err, gc.IsNil)
	}

	var tests = []struct {
		query        string
		kind, digest string
		err, warn    string
		time         string
		revision     int
	}{
		{
			query:  url1.String(),
			digest: "revKey3",
			kind:   "publish-error",
			err:    "An error.",
			time:   "1970-01-01T00:00:03Z",
		}, {
			query:    url2.String(),
			digest:   "revKey2",
			kind:     "published",
			revision: 43,
			time:     "1970-01-01T00:00:02Z",
		}, {
			query:    url1.String() + "@revKey1",
			digest:   "revKey1",
			kind:     "published",
			revision: 42,
			warn:     "A warning.",
			time:     "1970-01-01T00:00:01Z",
		}, {
			query:    "cs:non/existent",
			revision: 0,
			err:      "entry not found",
		},
	}

	for _, t := range tests {
		req.Form = url.Values{"charms": []string{t.query}}
		rec := httptest.NewRecorder()
		server.ServeHTTP(rec, req)

		url := t.query
		if i := strings.Index(url, "@"); i >= 0 {
			url = url[:i]
		}
		info := map[string]interface{}{
			"kind":     "",
			"revision": float64(0),
		}
		if t.kind != "" {
			info["kind"] = t.kind
			info["revision"] = float64(t.revision)
			info["digest"] = t.digest
			info["time"] = t.time
		}
		if t.err != "" {
			info["errors"] = []interface{}{t.err}
		}
		if t.warn != "" {
			info["warnings"] = []interface{}{t.warn}
		}
		expected := map[string]interface{}{url: info}
		obtained := map[string]interface{}{}
		err = json.NewDecoder(rec.Body).Decode(&obtained)
		c.Assert(err, gc.IsNil)
		c.Assert(obtained, gc.DeepEquals, expected)
		c.Assert(rec.Header().Get("Content-Type"), gc.Equals, "application/json")
	}

	s.checkCounterSum(c, []string{"charm-event", "oneiric", "wordpress"}, false, 2)
	s.checkCounterSum(c, []string{"charm-event", "oneiric", "mysql"}, false, 1)

	query1 := url1.String() + "@" + event1.Digest
	query3 := url1.String() + "@" + event3.Digest
	event1Info := map[string]interface{}{
		"kind":     "published",
		"revision": float64(42),
		"digest":   "revKey1",
		"warnings": []interface{}{"A warning."},
		"time":     "1970-01-01T00:00:01Z"}
	event3Info := map[string]interface{}{
		"kind":     "publish-error",
		"revision": float64(0),
		"digest":   "revKey3",
		"errors":   []interface{}{"An error."},
		"time":     "1970-01-01T00:00:03Z"}

	req.Form = url.Values{"charms": []string{query1, query3}}
	rec := httptest.NewRecorder()
	server.ServeHTTP(rec, req)
	expected := map[string]interface{}{url1.String(): event3Info}
	obtained := map[string]interface{}{}
	err = json.NewDecoder(rec.Body).Decode(&obtained)
	c.Assert(err, gc.IsNil)
	c.Assert(obtained, jc.DeepEquals, expected)

	req.Form = url.Values{"charms": []string{query1, query3}, "long_keys": []string{"1"}}
	rec = httptest.NewRecorder()
	server.ServeHTTP(rec, req)
	expected = map[string]interface{}{query1: event1Info, query3: event3Info}
	obtained = map[string]interface{}{}
	err = json.NewDecoder(rec.Body).Decode(&obtained)
	c.Assert(err, gc.IsNil)
	c.Assert(obtained, jc.DeepEquals, expected)
}