Example #1
0
// bindUnit handles the bind-service message, binding a unit to all service
// instances bound to the app.
func bindUnit(msg *queue.Message) error {
	a := App{Name: msg.Args[0]}
	err := a.Get()
	if err != nil {
		msg.Delete()
		return fmt.Errorf("Error handling %q: app %q does not exist.", msg.Action, a.Name)
	}
	conn, err := db.Conn()
	if err != nil {
		return fmt.Errorf("Error handling %q: %s", msg.Action, err)
	}
	defer conn.Close()
	units := getUnits(&a, msg.Args[1:])
	if len(units) == 0 {
		msg.Delete()
		return errors.New("Unknown unit in the message.")
	}
	unit := units[0]
	var instances []service.ServiceInstance
	q := bson.M{"apps": bson.M{"$in": []string{msg.Args[0]}}}
	err = conn.ServiceInstances().Find(q).All(&instances)
	if err != nil {
		return err
	}
	for _, instance := range instances {
		_, err = instance.BindUnit(&a, &unit)
		if err != nil {
			log.Printf("Error binding the unit %s with the service instance %s.", unit.Name, instance.Name)
		}
	}
	return nil
}
Example #2
0
func handle(msg *queue.Message) {
	if msg.Action == addUnitToLoadBalancer {
		if len(msg.Args) < 1 {
			log.Printf("Failed to handle %q: it requires at least one argument.", msg.Action)
			msg.Delete()
			return
		}
		a := qApp{name: msg.Args[0]}
		unitNames := msg.Args[1:]
		sort.Strings(unitNames)
		status, err := (&JujuProvisioner{}).collectStatus()
		if err != nil {
			log.Printf("Failed to handle %q: juju status failed.\n%s.", msg.Action, err)
			return
		}
		var units []provision.Unit
		for _, u := range status {
			if u.AppName != a.name {
				continue
			}
			n := sort.SearchStrings(unitNames, u.Name)
			if len(unitNames) == 0 ||
				n < len(unitNames) && unitNames[n] == u.Name {
				units = append(units, u)
			}
		}
		if len(units) == 0 {
			log.Printf("Failed to handle %q: units not found.", msg.Action)
			msg.Delete()
			return
		}
		var noId []string
		var ok []provision.Unit
		for _, u := range units {
			if u.InstanceId == "pending" || u.InstanceId == "" {
				noId = append(noId, u.Name)
			} else {
				ok = append(ok, u)
			}
		}
		if len(noId) == len(units) {
			getQueue(queueName).Release(msg, 0)
		} else {
			manager := ELBManager{}
			manager.Register(&a, ok...)
			msg.Delete()
			if len(noId) > 0 {
				args := []string{a.name}
				args = append(args, noId...)
				msg := queue.Message{
					Action: msg.Action,
					Args:   args,
				}
				getQueue(queueName).Put(&msg, 1e9)
			}
		}
	} else {
		msg.Delete()
	}
}
Example #3
0
// handle is the function called by the queue handler on each message.
func handle(msg *queue.Message) {
	switch msg.Action {
	case RegenerateApprcAndStart:
		fallthrough
	case regenerateApprc:
		if len(msg.Args) < 1 {
			log.Printf("Error handling %q: this action requires at least 1 argument.", msg.Action)
			msg.Delete()
			return
		}
		app, err := ensureAppIsStarted(msg)
		if err != nil {
			log.Print(err)
			return
		}
		msg.Delete()
		app.SerializeEnvVars()
		fallthrough
	case startApp:
		if msg.Action == regenerateApprc {
			break
		}
		if len(msg.Args) < 1 {
			log.Printf("Error handling %q: this action requires at least 1 argument.", msg.Action)
		}
		app, err := ensureAppIsStarted(msg)
		if err != nil {
			log.Print(err)
			return
		}
		err = app.Restart(ioutil.Discard)
		if err != nil {
			log.Printf("Error handling %q. App failed to start:\n%s.", msg.Action, err)
			return
		}
		msg.Delete()
	case BindService:
		err := bindUnit(msg)
		if err != nil {
			log.Print(err)
			return
		}
		msg.Delete()
	default:
		log.Printf("Error handling %q: invalid action.", msg.Action)
		msg.Delete()
	}
}
Example #4
0
// ensureAppIsStarted make sure that the app and all units present in the given
// message are started.
func ensureAppIsStarted(msg *queue.Message) (App, error) {
	a := App{Name: msg.Args[0]}
	err := a.Get()
	if err != nil {
		msg.Delete()
		return a, fmt.Errorf("Error handling %q: app %q does not exist.", msg.Action, a.Name)
	}
	units := getUnits(&a, msg.Args[1:])
	if len(msg.Args) > 1 && len(units) == 0 {
		msg.Delete()
		format := "Error handling %q for the app %q: unknown units in the message. Deleting it..."
		return a, fmt.Errorf(format, msg.Action, a.Name)
	}
	if !a.Available() || !units.Started() {
		format := "Error handling %q for the app %q:"
		uState := units.State()
		if uState == "error" || uState == "down" {
			format += fmt.Sprintf(" units are in %q state.", uState)
			msg.Delete()
		} else {
			format += " all units must be started."
		}
		return a, fmt.Errorf(format, msg.Action, a.Name)
	}
	return a, nil
}
Example #5
0
func (s *S) TestHandleMessageErrors(c *gocheck.C) {
	var data = []struct {
		action      string
		args        []string
		unitName    string
		expectedLog string
	}{
		{
			action:      "unknown-action",
			args:        []string{"does not matter"},
			expectedLog: `Error handling "unknown-action": invalid action.`,
		},
		{
			action: startApp,
			args:   []string{"nemesis"},
			expectedLog: `Error handling "start-app" for the app "nemesis":` +
				` all units must be started.`,
		},
		{
			action: startApp,
			args:   []string{"totem", "totem/0", "totem/1"},
			expectedLog: `Error handling "start-app" for the app "totem":` +
				` all units must be started.`,
		},
		{
			action: regenerateApprc,
			args:   []string{"nemesis"},
			expectedLog: `Error handling "regenerate-apprc" for the app "nemesis":` +
				` all units must be started.`,
		},
		{
			action: regenerateApprc,
			args:   []string{"totem", "totem/0", "totem/1"},
			expectedLog: `Error handling "regenerate-apprc" for the app "totem":` +
				` all units must be started.`,
		},
		{
			action:      regenerateApprc,
			args:        []string{"unknown-app"},
			expectedLog: `Error handling "regenerate-apprc": app "unknown-app" does not exist.`,
		},
		{
			action:      regenerateApprc,
			expectedLog: `Error handling "regenerate-apprc": this action requires at least 1 argument.`,
		},
		{
			action: regenerateApprc,
			args:   []string{"marathon", "marathon/0"},
			expectedLog: `Error handling "regenerate-apprc" for the app "marathon":` +
				` units are in "error" state.`,
		},
		{
			action: regenerateApprc,
			args:   []string{"territories", "territories/0"},
			expectedLog: `Error handling "regenerate-apprc" for the app "territories":` +
				` units are in "down" state.`,
		},
	}
	a := App{Name: "nemesis"}
	err := s.conn.Apps().Insert(a)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Apps().Remove(bson.M{"name": a.Name})
	a = App{
		Name: "totem",
		Units: []Unit{
			{Name: "totem/0", State: "pending"},
			{Name: "totem/1", State: "started"},
		},
	}
	err = s.conn.Apps().Insert(a)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Apps().Remove(bson.M{"name": a.Name})
	a = App{Name: "marathon", Units: []Unit{{Name: "marathon/0", State: "error"}}}
	err = s.conn.Apps().Insert(a)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Apps().Remove(bson.M{"name": a.Name})
	a = App{Name: "territories", Units: []Unit{{Name: "territories/0", State: "down"}}}
	err = s.conn.Apps().Insert(a)
	c.Assert(err, gocheck.IsNil)
	defer s.conn.Apps().Remove(bson.M{"name": a.Name})
	logger := testing.NewFakeLogger().(*testing.FakeLogger)
	for _, d := range data {
		message := queue.Message{Action: d.action}
		if len(d.args) > 0 {
			message.Args = d.args
		}
		handle(&message)
	}
	content := logger.Buf.String()
	lines := strings.Split(content, "\n")
	for i, d := range data {
		if lines[i] != d.expectedLog {
			c.Errorf("\nWant: %q.\nGot:\n%s", d.expectedLog, content)
		}
	}
}
Example #6
0
func (s *S) TestHandleMessageErrors(c *C) {
	var data = []struct {
		action      string
		args        []string
		unitName    string
		expectedLog string
		visits      int
	}{
		{
			action:      "unknown-action",
			args:        []string{"does not matter"},
			expectedLog: `Error handling "unknown-action": invalid action.`,
		},
		{
			action: app.StartApp,
			args:   []string{"nemesis"},
			expectedLog: `Error handling "start-app" for the app "nemesis":` +
				` The status of the app and all units should be "started" (the app is "pending").`,
		},
		{
			action: app.StartApp,
			args:   []string{"totem", "totem/0", "totem/1"},
			expectedLog: `Error handling "start-app" for the app "totem":` +
				` The status of the app and all units should be "started" (the app is "started").`,
		},
		{
			action: app.RegenerateApprc,
			args:   []string{"nemesis"},
			expectedLog: `Error handling "regenerate-apprc" for the app "nemesis":` +
				` The status of the app and all units should be "started" (the app is "pending").`,
		},
		{
			action: app.RegenerateApprc,
			args:   []string{"totem", "totem/0", "totem/1"},
			expectedLog: `Error handling "regenerate-apprc" for the app "totem":` +
				` The status of the app and all units should be "started" (the app is "started").`,
		},
		{
			action:      app.RegenerateApprc,
			args:        []string{"unknown-app"},
			expectedLog: `Error handling "regenerate-apprc": app "unknown-app" does not exist.`,
		},
		{
			action:      app.RegenerateApprc,
			expectedLog: `Error handling "regenerate-apprc": this action requires at least 1 argument.`,
		},
		{
			action:      "does not matter",
			args:        []string{"does not matter"},
			expectedLog: `Error handling "does not matter": this message has been visited more than 50 times.`,
			visits:      MaxVisits,
		},
		{
			action: app.RegenerateApprc,
			args:   []string{"marathon"},
			expectedLog: `Error handling "regenerate-apprc" for the app "marathon":` +
				` the app is in "error" state.`,
		},
		{
			action: app.RegenerateApprc,
			args:   []string{"territories"},
			expectedLog: `Error handling "regenerate-apprc" for the app "territories":` +
				` the app is down.`,
		},
	}
	var buf bytes.Buffer
	a := app.App{Name: "nemesis", State: "pending"}
	err := db.Session.Apps().Insert(a)
	c.Assert(err, IsNil)
	defer db.Session.Apps().Remove(bson.M{"name": a.Name})
	a = app.App{
		Name:  "totem",
		State: "started",
		Units: []app.Unit{
			{Name: "totem/0", State: "pending"},
			{Name: "totem/1", State: "started"},
		},
	}
	err = db.Session.Apps().Insert(a)
	c.Assert(err, IsNil)
	defer db.Session.Apps().Remove(bson.M{"name": a.Name})
	a = app.App{Name: "marathon", State: "error"}
	err = db.Session.Apps().Insert(a)
	c.Assert(err, IsNil)
	defer db.Session.Apps().Remove(bson.M{"name": a.Name})
	a = app.App{Name: "territories", State: "down"}
	err = db.Session.Apps().Insert(a)
	c.Assert(err, IsNil)
	defer db.Session.Apps().Remove(bson.M{"name": a.Name})
	log.SetLogger(stdlog.New(&buf, "", 0))
	handler := MessageHandler{}
	handler.start()
	handler.closed = 1
	defer handler.stop()
	for _, d := range data {
		message := queue.Message{
			Action: d.action,
			Visits: d.visits,
		}
		if len(d.args) > 0 {
			message.Args = d.args
		}
		handler.handle(message)
	}
	content := buf.String()
	lines := strings.Split(content, "\n")
	for i, d := range data {
		var found bool
		for j := i; j < len(lines); j++ {
			if lines[j] == d.expectedLog {
				found = true
				break
			}
		}
		if !found {
			c.Errorf("\nWant: %q.\nGot:\n%s", d.expectedLog, content)
		}
	}
}