Example #1
0
func (s *S) TestCreateDeployment(c *C) {
	app := s.createTestApp(c, &ct.App{Name: "create-deployment"})
	release := s.createTestRelease(c, &ct.Release{
		Processes: map[string]ct.ProcessType{"web": {}},
	})
	c.Assert(s.c.PutFormation(&ct.Formation{
		AppID:     app.ID,
		ReleaseID: release.ID,
		Processes: map[string]int{"web": 1},
	}), IsNil)
	defer s.c.DeleteFormation(app.ID, release.ID)

	// deploying an initial release should no-op
	d, err := s.c.CreateDeployment(app.ID, release.ID)
	c.Assert(err, IsNil)
	c.Assert(d.FinishedAt, NotNil)
	// but the app release should now be set
	gotRelease, err := s.c.GetAppRelease(app.ID)
	c.Assert(release.ID, Equals, gotRelease.ID)

	newRelease := s.createTestRelease(c, &ct.Release{})

	d, err = s.c.CreateDeployment(app.ID, newRelease.ID)
	c.Assert(err, IsNil)
	c.Assert(d.ID, Not(Equals), "")
	c.Assert(d.AppID, Equals, app.ID)
	c.Assert(d.NewReleaseID, Equals, newRelease.ID)
	c.Assert(d.OldReleaseID, Equals, release.ID)
	c.Assert(d.DeployTimeout, Equals, app.DeployTimeout)

	// quickly recreating a deployment should error
	_, err = s.c.CreateDeployment(app.ID, newRelease.ID)
	c.Assert(hh.IsValidationError(err), Equals, true)
	c.Assert(err.(hh.JSONError).Message, Equals, "Cannot create deploy, there is already one in progress for this app.")
}
Example #2
0
func (s *S) TestCreateFormation(c *C) {
	for i, useName := range []bool{false, true} {
		release := s.createTestRelease(c, &ct.Release{
			Processes: map[string]ct.ProcessType{"web": {}},
		})
		app := s.createTestApp(c, &ct.App{Name: fmt.Sprintf("create-formation-%d", i)})

		// First create a formation with an invalid process type. Will fail.
		in := &ct.Formation{ReleaseID: release.ID, AppID: app.ID, Processes: map[string]int{"foo": 1}}
		if useName {
			in.AppID = app.Name
		}
		err := s.c.PutFormation(in)
		c.Assert(hh.IsValidationError(err), Equals, true)

		// Now edit the formation to have valid process types. Should succeed.
		in.Processes = map[string]int{"web": 1}
		out := s.createTestFormation(c, in)
		defer s.deleteTestFormation(out)
		c.Assert(out.AppID, Equals, app.ID)
		c.Assert(out.ReleaseID, Equals, release.ID)
		c.Assert(out.Processes["web"], Equals, 1)

		var appID string
		if useName {
			appID = app.Name
		} else {
			appID = app.ID
		}
		gotFormation, err := s.c.GetFormation(appID, release.ID)
		c.Assert(err, IsNil)
		c.Assert(gotFormation, DeepEquals, out)

		expanded, err := s.c.GetExpandedFormation(appID, release.ID)
		c.Assert(err, IsNil)
		c.Assert(expanded.App.ID, Equals, app.ID)
		c.Assert(expanded.Release.ID, Equals, release.ID)
		c.Assert(expanded.Artifacts, HasLen, len(release.ArtifactIDs))
		for i, id := range release.ArtifactIDs {
			c.Assert(expanded.Artifacts[i].ID, Equals, id)
		}
		c.Assert(expanded.Processes, DeepEquals, out.Processes)

		_, err = s.c.GetFormation(appID, release.ID+"fail")
		c.Assert(err, Equals, controller.ErrNotFound)
	}
}
Example #3
0
File: main.go Project: kgrz/flynn
func (c *context) watchHost(h *cluster.Host, ready chan struct{}) {
	if !c.hosts.Add(h.ID()) {
		if ready != nil {
			ready <- struct{}{}
		}
		return
	}
	defer c.hosts.Remove(h.ID())

	g := grohl.NewContext(grohl.Data{"fn": "watchHost", "host.id": h.ID()})

	c.hosts.Set(h.ID(), h)

	g.Log(grohl.Data{"at": "start"})

	ch := make(chan *host.Event)
	h.StreamEvents("all", ch)
	if ready != nil {
		ready <- struct{}{}
	}

	// Call PutJob in a goroutine so we don't block receiving job events whilst potentially
	// making multiple requests to the controller (e.g. if the controller is down).
	//
	// Use a channel (rather than spawning a goroutine per event) so that events are delivered in order.
	jobs := make(chan *ct.Job, 10)
	go func() {
		for job := range jobs {
			putJobAttempts.Run(func() error {
				if err := c.PutJob(job); err != nil {
					g.Log(grohl.Data{"at": "put_job_error", "job.id": job.ID, "state": job.State, "err": err})
					// ignore validation / not found errors
					if httphelper.IsValidationError(err) || err == controller.ErrNotFound {
						return nil
					}
					return err
				}
				g.Log(grohl.Data{"at": "put_job", "job.id": job.ID, "state": job.State})
				return nil
			})
		}
	}()

	for event := range ch {
		meta := event.Job.Job.Metadata
		appID := meta["flynn-controller.app"]
		releaseID := meta["flynn-controller.release"]
		jobType := meta["flynn-controller.type"]

		if appID == "" || releaseID == "" {
			continue
		}

		job := &ct.Job{
			ID:        event.JobID,
			AppID:     appID,
			ReleaseID: releaseID,
			Type:      jobType,
			State:     jobState(event),
			Meta:      jobMetaFromMetadata(meta),
		}
		g.Log(grohl.Data{"at": "event", "job.id": event.JobID, "event": event.Event})
		jobs <- job

		// get a read lock on the mutex to ensure we are not currently
		// syncing with the cluster
		c.mtx.RLock()
		j := c.jobs.Get(h.ID(), event.JobID)
		c.mtx.RUnlock()
		if j == nil {
			continue
		}
		j.startedAt = event.Job.StartedAt

		if event.Event != "error" && event.Event != "stop" {
			continue
		}
		g.Log(grohl.Data{"at": "remove", "job.id": event.JobID, "event": event.Event})

		c.jobs.Remove(h.ID(), event.JobID)
		go func(event *host.Event) {
			c.mtx.RLock()
			j.Formation.RestartJob(jobType, h.ID(), event.JobID)
			c.mtx.RUnlock()
		}(event)
	}
	// TODO: check error/reconnect
}
Example #4
0
func (s *HTTPSuite) TestManualLeaderElection(c *C) {
	// service with auto election should not support manual leader
	err := s.client.Service("a").SetLeader("123")
	c.Assert(hh.IsValidationError(err), Equals, true)

	// create service with manual config
	err = s.client.AddService("b", &discoverd.ServiceConfig{LeaderType: discoverd.LeaderTypeManual})
	c.Assert(err, IsNil)

	// register instance
	inst1 := fakeInstance()
	hb1, err := s.client.RegisterInstance("b", inst1)
	c.Assert(err, IsNil)
	defer hb1.Close()

	// no leader event when starting watch
	events := make(chan *discoverd.Event, 2)
	s.state.Subscribe("b", true, discoverd.EventKindUp|discoverd.EventKindDown|discoverd.EventKindLeader|discoverd.EventKindCurrent, events)
	assertEvent(c, events, "b", discoverd.EventKindUp, inst1)
	assertEvent(c, events, "b", discoverd.EventKindCurrent, nil)

	// get leader should 404
	srv := s.client.Service("b")
	_, err = srv.Leader()
	c.Assert(discoverd.IsNotFound(err), Equals, true)

	// set leader
	err = srv.SetLeader(inst1.ID)
	c.Assert(err, IsNil)
	leader, err := srv.Leader()
	c.Assert(err, IsNil)
	assertInstanceEqual(c, leader, inst1)
	assertEvent(c, events, "b", discoverd.EventKindLeader, inst1)

	// add another instance and set to leader
	inst2 := fakeInstance()
	hb2, err := s.client.RegisterInstance("b", inst2)
	c.Assert(err, IsNil)
	defer hb2.Close()
	assertEvent(c, events, "b", discoverd.EventKindUp, inst2)

	err = srv.SetLeader(inst2.ID)
	c.Assert(err, IsNil)
	assertEvent(c, events, "b", discoverd.EventKindLeader, inst2)
	leader, err = srv.Leader()
	c.Assert(err, IsNil)
	assertInstanceEqual(c, leader, inst2)

	// remove leader instance
	hb2.Close()
	assertEvent(c, events, "b", discoverd.EventKindDown, inst2)
	// get leader should 404, no event
	_, err = srv.Leader()
	c.Assert(discoverd.IsNotFound(err), Equals, true)
	assertNoEvent(c, events)

	// set leader to instance 1
	err = srv.SetLeader(inst1.ID)
	c.Assert(err, IsNil)
	assertEvent(c, events, "b", discoverd.EventKindLeader, inst1)
	leader, err = srv.Leader()
	c.Assert(err, IsNil)
	assertInstanceEqual(c, leader, inst1)
}