func (s server) GetMinionConfig(cts context.Context, _ *pb.Request) (*pb.MinionConfig, error) { var cfg pb.MinionConfig if m, err := s.MinionSelf(); err == nil { cfg.Role = db.RoleToPB(m.Role) cfg.PrivateIP = m.PrivateIP cfg.Spec = m.Spec cfg.Provider = m.Provider cfg.Size = m.Size cfg.Region = m.Region } else { cfg.Role = db.RoleToPB(db.None) } return &cfg, nil }
func (fm *foreman) runOnce() { var machines []db.Machine fm.conn.Transact(func(view db.Database) error { machines = view.SelectFromMachine(func(m db.Machine) bool { return m.PublicIP != "" && m.PrivateIP != "" && m.CloudID != "" }) fm.spec = "" clst, _ := view.GetCluster() fm.spec = clst.Spec return nil }) fm.updateMinionMap(machines) /* Request the current configuration from each minion. */ fm.forEachMinion(func(m *minion) { var err error m.config, err = m.client.getMinion() connected := err == nil if connected && !m.connected { log.WithField("machine", m.machine).Info("New connection.") } m.connected = connected }) var etcdIPs []string for _, m := range fm.minions { if m.machine.Role == db.Master && m.machine.PrivateIP != "" { etcdIPs = append(etcdIPs, m.machine.PrivateIP) } } // Assign all of the minions their new configs fm.forEachMinion(func(m *minion) { if !m.connected { return } newConfig := pb.MinionConfig{ Role: db.RoleToPB(m.machine.Role), PrivateIP: m.machine.PrivateIP, Spec: fm.spec, Provider: string(m.machine.Provider), Size: m.machine.Size, Region: m.machine.Region, } if newConfig == m.config { return } if err := m.client.setMinion(newConfig); err != nil { return } if err := m.client.bootEtcd(pb.EtcdMembers{IPs: etcdIPs}); err != nil { log.WithError(err).Warn("Failed send etcd members.") } }) }
// RunOnce should be called regularly to allow the foreman to update minion roles. func RunOnce(conn db.Conn) { var spec string var machines []db.Machine conn.Transact(func(view db.Database) error { machines = view.SelectFromMachine(func(m db.Machine) bool { return m.PublicIP != "" && m.PrivateIP != "" && m.CloudID != "" }) clst, _ := view.GetCluster() spec = clst.Spec return nil }) updateMinionMap(machines) /* Request the current configuration from each minion. */ forEachMinion(func(m *minion) { var err error m.config, err = m.client.getMinion() connected := err == nil if connected && !m.connected { log.WithField("machine", m.machine).Debug("New connection.") } if connected != m.machine.Connected { conn.Transact(func(view db.Database) error { m.machine.Connected = connected view.Commit(m.machine) return nil }) } m.connected = connected }) var etcdIPs []string for _, m := range minions { if m.machine.Role == db.Master && m.machine.PrivateIP != "" { etcdIPs = append(etcdIPs, m.machine.PrivateIP) } } // Assign all of the minions their new configs forEachMinion(func(m *minion) { if !m.connected { return } newConfig := pb.MinionConfig{ Role: db.RoleToPB(m.machine.Role), PrivateIP: m.machine.PrivateIP, Spec: spec, Provider: string(m.machine.Provider), Size: m.machine.Size, Region: m.machine.Region, EtcdMembers: etcdIPs, AuthorizedKeys: m.machine.SSHKeys, } if reflect.DeepEqual(newConfig, m.config) { return } if err := m.client.setMinion(newConfig); err != nil { log.WithError(err).Error("Failed to set minion config.") return } }) }
func TestConfigConsistency(t *testing.T) { masterRole := db.RoleToPB(db.Master) workerRole := db.RoleToPB(db.Worker) fm, _ := startTest() var master, worker db.Machine fm.conn.Transact(func(view db.Database) error { master = view.InsertMachine() master.PublicIP = "1.1.1.1" master.PrivateIP = master.PublicIP master.CloudID = "ID1" view.Commit(master) worker = view.InsertMachine() worker.PublicIP = "2.2.2.2" worker.PrivateIP = worker.PublicIP worker.CloudID = "ID2" view.Commit(worker) return nil }) fm.init() fm.conn.Transact(func(view db.Database) error { master.Role = db.Master worker.Role = db.Worker view.Commit(master) view.Commit(worker) return nil }) fm.runOnce() checkRoles := func(fore foreman) { r := fore.minions["1.1.1.1"].client.(*fakeClient).mc.Role if r != masterRole { t.Errorf("Master has role %v, should be %v", r, masterRole) } r = fore.minions["2.2.2.2"].client.(*fakeClient).mc.Role if r != workerRole { t.Errorf("Worker has role %v, should be %v", r, workerRole) } } checkRoles(fm) fm.stop() newfm, clients := startTest() newfm.conn = fm.conn // Insert the clients into the client list to simulate fetching // from the remote cluster clients.clients["1.1.1.1"] = &fakeClient{clients, "1.1.1.1", pb.MinionConfig{Role: masterRole}, pb.EtcdMembers{}} clients.clients["2.2.2.2"] = &fakeClient{clients, "2.2.2.2", pb.MinionConfig{Role: workerRole}, pb.EtcdMembers{}} newfm.init() newfm.runOnce() checkRoles(newfm) // After many runs, the roles should never change for i := 0; i < 25; i++ { newfm.runOnce() } checkRoles(newfm) // Ensure that the DB machines have the correct roles as well. newfm.conn.Transact(func(view db.Database) error { machines := view.SelectFromMachine(nil) for _, m := range machines { if m.PublicIP == "1.1.1.1" && m.Role != db.Master { t.Errorf("db Master had role %v, expected %v", m.Role, db.Master) } if m.PublicIP == "2.2.2.2" && m.Role != db.Worker { t.Errorf("db Worker had role %v, expected %v", m.Role, db.Worker) } } return nil }) }
func TestConfigConsistency(t *testing.T) { masterRole := db.RoleToPB(db.Master) workerRole := db.RoleToPB(db.Worker) conn, clients := startTest() var master, worker db.Machine conn.Transact(func(view db.Database) error { master = view.InsertMachine() master.PublicIP = "1.1.1.1" master.PrivateIP = master.PublicIP master.CloudID = "ID1" view.Commit(master) worker = view.InsertMachine() worker.PublicIP = "2.2.2.2" worker.PrivateIP = worker.PublicIP worker.CloudID = "ID2" view.Commit(worker) return nil }) Init(conn) conn.Transact(func(view db.Database) error { master.Role = db.Master worker.Role = db.Worker view.Commit(master) view.Commit(worker) return nil }) RunOnce(conn) checkRoles := func() { r := minions["1.1.1.1"].client.(*fakeClient).mc.Role assert.Equal(t, masterRole, r) r = minions["2.2.2.2"].client.(*fakeClient).mc.Role assert.Equal(t, workerRole, r) } checkRoles() minions = map[string]*minion{} // Insert the clients into the client list to simulate fetching // from the remote cluster clients.clients["1.1.1.1"] = &fakeClient{clients, "1.1.1.1", pb.MinionConfig{Role: masterRole}} clients.clients["2.2.2.2"] = &fakeClient{clients, "2.2.2.2", pb.MinionConfig{Role: workerRole}} Init(conn) RunOnce(conn) checkRoles() // After many runs, the roles should never change for i := 0; i < 25; i++ { RunOnce(conn) } checkRoles() // Ensure that the DB machines have the correct roles as well. conn.Transact(func(view db.Database) error { machines := view.SelectFromMachine(nil) for _, m := range machines { if m.PublicIP == "1.1.1.1" { assert.Equal(t, db.Role(db.Master), m.Role) } if m.PublicIP == "2.2.2.2" { assert.Equal(t, db.Role(db.Worker), m.Role) } } return nil }) }