func (s *ConsulSuite) TestDatastore(c *check.C) { s.setupConsul(c) consulHost := s.composeProject.Container(c, "consul").NetworkSettings.IPAddress kvSource, err := staert.NewKvSource(store.CONSUL, []string{consulHost + ":8500"}, &store.Config{ ConnectionTimeout: 10 * time.Second, }, "traefik") c.Assert(err, checker.IsNil) ctx := context.Background() datastore1, err := cluster.NewDataStore(ctx, *kvSource, &TestStruct{}, nil) c.Assert(err, checker.IsNil) datastore2, err := cluster.NewDataStore(ctx, *kvSource, &TestStruct{}, nil) c.Assert(err, checker.IsNil) setter1, _, err := datastore1.Begin() c.Assert(err, checker.IsNil) err = setter1.Commit(&TestStruct{ String: "foo", Int: 1, }) c.Assert(err, checker.IsNil) time.Sleep(2 * time.Second) test1 := datastore1.Get().(*TestStruct) c.Assert(test1.String, checker.Equals, "foo") test2 := datastore2.Get().(*TestStruct) c.Assert(test2.String, checker.Equals, "foo") setter2, _, err := datastore2.Begin() c.Assert(err, checker.IsNil) err = setter2.Commit(&TestStruct{ String: "bar", Int: 2, }) c.Assert(err, checker.IsNil) time.Sleep(2 * time.Second) test1 = datastore1.Get().(*TestStruct) c.Assert(test1.String, checker.Equals, "bar") test2 = datastore2.Get().(*TestStruct) c.Assert(test2.String, checker.Equals, "bar") wg := &sync.WaitGroup{} wg.Add(4) go func() { for i := 0; i < 100; i++ { setter1, _, err := datastore1.Begin() c.Assert(err, checker.IsNil) err = setter1.Commit(&TestStruct{ String: "datastore1", Int: i, }) c.Assert(err, checker.IsNil) } wg.Done() }() go func() { for i := 0; i < 100; i++ { setter2, _, err := datastore2.Begin() c.Assert(err, checker.IsNil) err = setter2.Commit(&TestStruct{ String: "datastore2", Int: i, }) c.Assert(err, checker.IsNil) } wg.Done() }() go func() { for i := 0; i < 100; i++ { test1 := datastore1.Get().(*TestStruct) c.Assert(test1, checker.NotNil) } wg.Done() }() go func() { for i := 0; i < 100; i++ { test2 := datastore2.Get().(*TestStruct) c.Assert(test2, checker.NotNil) } wg.Done() }() wg.Wait() }
// CreateClusterConfig creates a tls.config using ACME configuration in cluster mode func (a *ACME) CreateClusterConfig(leadership *cluster.Leadership, tlsConfig *tls.Config, checkOnDemandDomain func(domain string) bool) error { err := a.init() if err != nil { return err } if len(a.Storage) == 0 { return errors.New("Empty Store, please provide a key for certs storage") } a.checkOnDemandDomain = checkOnDemandDomain tlsConfig.Certificates = append(tlsConfig.Certificates, *a.defaultCertificate) tlsConfig.GetCertificate = a.getCertificate listener := func(object cluster.Object) error { account := object.(*Account) account.Init() if !leadership.IsLeader() { a.client, err = a.buildACMEClient(account) if err != nil { log.Errorf("Error building ACME client %+v: %s", object, err.Error()) } } return nil } datastore, err := cluster.NewDataStore( leadership.Pool.Ctx(), staert.KvSource{ Store: leadership.Store, Prefix: a.Storage, }, &Account{}, listener) if err != nil { return err } a.store = datastore a.challengeProvider = &challengeProvider{store: a.store} ticker := time.NewTicker(24 * time.Hour) leadership.Pool.AddGoCtx(func(ctx context.Context) { log.Infof("Starting ACME renew job...") defer log.Infof("Stopped ACME renew job...") for { select { case <-ctx.Done(): return case <-ticker.C: if err := a.renewCertificates(); err != nil { log.Errorf("Error renewing ACME certificate: %s", err.Error()) } } } }) leadership.AddListener(func(elected bool) error { if elected { object, err := a.store.Load() if err != nil { return err } transaction, object, err := a.store.Begin() if err != nil { return err } account := object.(*Account) account.Init() var needRegister bool if account == nil || len(account.Email) == 0 { account, err = NewAccount(a.Email) if err != nil { return err } needRegister = true } if err != nil { return err } a.client, err = a.buildACMEClient(account) if err != nil { return err } if needRegister { // New users will need to register; be sure to save it log.Debugf("Register...") reg, err := a.client.Register() if err != nil { return err } account.Registration = reg } // The client has a URL to the current Let's Encrypt Subscriber // Agreement. The user will need to agree to it. log.Debugf("AgreeToTOS...") err = a.client.AgreeToTOS() if err != nil { // Let's Encrypt Subscriber Agreement renew ? reg, err := a.client.QueryRegistration() if err != nil { return err } account.Registration = reg err = a.client.AgreeToTOS() if err != nil { log.Errorf("Error sending ACME agreement to TOS: %+v: %s", account, err.Error()) } } err = transaction.Commit(account) if err != nil { return err } safe.Go(func() { a.retrieveCertificates() if err := a.renewCertificates(); err != nil { log.Errorf("Error renewing ACME certificate %+v: %s", account, err.Error()) } }) } return nil }) return nil }