2019-02-21 15:08:30 +00:00
|
|
|
// Copyright 2019 Sorint.lab
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package configstore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/tls"
|
|
|
|
"net/http"
|
|
|
|
"path/filepath"
|
2019-07-17 17:52:25 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
2019-02-21 15:08:30 +00:00
|
|
|
|
2019-07-01 09:40:20 +00:00
|
|
|
scommon "agola.io/agola/internal/common"
|
|
|
|
"agola.io/agola/internal/datamanager"
|
|
|
|
"agola.io/agola/internal/etcd"
|
|
|
|
"agola.io/agola/internal/objectstorage"
|
|
|
|
"agola.io/agola/internal/services/config"
|
|
|
|
action "agola.io/agola/internal/services/configstore/action"
|
|
|
|
"agola.io/agola/internal/services/configstore/api"
|
2019-07-17 17:52:25 +00:00
|
|
|
"agola.io/agola/internal/services/configstore/common"
|
2019-07-01 09:40:20 +00:00
|
|
|
"agola.io/agola/internal/services/configstore/readdb"
|
|
|
|
"agola.io/agola/internal/util"
|
2019-07-31 13:39:07 +00:00
|
|
|
"agola.io/agola/services/configstore/types"
|
2019-02-21 15:08:30 +00:00
|
|
|
|
|
|
|
"github.com/gorilla/mux"
|
2022-02-21 17:07:58 +00:00
|
|
|
"github.com/rs/zerolog"
|
|
|
|
"github.com/rs/zerolog/log"
|
2019-07-17 17:52:25 +00:00
|
|
|
etcdclientv3 "go.etcd.io/etcd/clientv3"
|
|
|
|
"go.etcd.io/etcd/mvcc/mvccpb"
|
2022-02-24 11:56:52 +00:00
|
|
|
errors "golang.org/x/xerrors"
|
2019-02-21 15:08:30 +00:00
|
|
|
)
|
|
|
|
|
2019-07-17 17:52:25 +00:00
|
|
|
func (s *Configstore) maintenanceModeWatcherLoop(ctx context.Context, runCtxCancel context.CancelFunc, maintenanceModeEnabled bool) {
|
|
|
|
for {
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Debug().Msgf("maintenanceModeWatcherLoop")
|
2019-07-17 17:52:25 +00:00
|
|
|
|
|
|
|
// at first watch restart from previous processed revision
|
|
|
|
if err := s.maintenanceModeWatcher(ctx, runCtxCancel, maintenanceModeEnabled); err != nil {
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Err(err).Send()
|
2019-07-17 17:52:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sleepCh := time.NewTimer(1 * time.Second).C
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case <-sleepCh:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Configstore) maintenanceModeWatcher(ctx context.Context, runCtxCancel context.CancelFunc, maintenanceModeEnabled bool) error {
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Info().Msgf("watcher: maintenance mode enabled: %t", maintenanceModeEnabled)
|
2019-07-17 17:52:25 +00:00
|
|
|
resp, err := s.e.Get(ctx, common.EtcdMaintenanceKey, 0)
|
2022-02-24 11:56:52 +00:00
|
|
|
if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) {
|
2019-07-17 17:52:25 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(resp.Kvs) > 0 {
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Info().Msgf("maintenance mode key is present")
|
2019-07-17 17:52:25 +00:00
|
|
|
if !maintenanceModeEnabled {
|
|
|
|
runCtxCancel()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
revision := resp.Header.Revision
|
|
|
|
|
|
|
|
wctx := etcdclientv3.WithRequireLeader(ctx)
|
|
|
|
|
|
|
|
// restart from previous processed revision
|
|
|
|
wch := s.e.Watch(wctx, common.EtcdMaintenanceKey, revision)
|
|
|
|
|
|
|
|
for wresp := range wch {
|
|
|
|
if wresp.Canceled {
|
|
|
|
return wresp.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, ev := range wresp.Events {
|
|
|
|
switch ev.Type {
|
|
|
|
case mvccpb.PUT:
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Info().Msgf("maintenance mode key set")
|
2019-07-17 17:52:25 +00:00
|
|
|
if !maintenanceModeEnabled {
|
|
|
|
runCtxCancel()
|
|
|
|
}
|
|
|
|
|
|
|
|
case mvccpb.DELETE:
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Info().Msgf("maintenance mode key removed")
|
2019-07-17 17:52:25 +00:00
|
|
|
if maintenanceModeEnabled {
|
|
|
|
runCtxCancel()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-05-07 21:42:42 +00:00
|
|
|
type Configstore struct {
|
2022-02-21 17:07:58 +00:00
|
|
|
log zerolog.Logger
|
2019-07-17 17:52:25 +00:00
|
|
|
c *config.Configstore
|
|
|
|
e *etcd.Store
|
|
|
|
dm *datamanager.DataManager
|
|
|
|
readDB *readdb.ReadDB
|
|
|
|
ost *objectstorage.ObjStorage
|
|
|
|
ah *action.ActionHandler
|
|
|
|
maintenanceMode bool
|
2019-02-21 15:08:30 +00:00
|
|
|
}
|
|
|
|
|
2022-02-21 17:07:58 +00:00
|
|
|
func NewConfigstore(ctx context.Context, log zerolog.Logger, c *config.Configstore) (*Configstore, error) {
|
2019-02-21 15:08:30 +00:00
|
|
|
if c.Debug {
|
2022-02-21 17:07:58 +00:00
|
|
|
log = log.Level(zerolog.DebugLevel)
|
2019-02-21 15:08:30 +00:00
|
|
|
}
|
|
|
|
|
2019-04-27 13:16:48 +00:00
|
|
|
ost, err := scommon.NewObjectStorage(&c.ObjectStorage)
|
2019-02-21 15:08:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-02-21 17:07:58 +00:00
|
|
|
e, err := scommon.NewEtcd(&c.Etcd, log, "configstore")
|
2019-02-21 15:08:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-05-07 21:42:42 +00:00
|
|
|
cs := &Configstore{
|
2022-02-21 17:07:58 +00:00
|
|
|
log: log,
|
2019-02-21 15:08:30 +00:00
|
|
|
c: c,
|
|
|
|
e: e,
|
2019-04-27 13:16:48 +00:00
|
|
|
ost: ost,
|
2019-02-21 15:08:30 +00:00
|
|
|
}
|
|
|
|
|
2019-04-26 14:00:03 +00:00
|
|
|
dmConf := &datamanager.DataManagerConfig{
|
2019-07-03 15:19:40 +00:00
|
|
|
BasePath: "configdata",
|
|
|
|
E: e,
|
|
|
|
OST: ost,
|
2019-04-26 14:00:03 +00:00
|
|
|
DataTypes: []string{
|
|
|
|
string(types.ConfigTypeUser),
|
|
|
|
string(types.ConfigTypeOrg),
|
2019-05-03 15:40:07 +00:00
|
|
|
string(types.ConfigTypeOrgMember),
|
2019-04-26 14:00:03 +00:00
|
|
|
string(types.ConfigTypeProjectGroup),
|
|
|
|
string(types.ConfigTypeProject),
|
|
|
|
string(types.ConfigTypeRemoteSource),
|
|
|
|
string(types.ConfigTypeSecret),
|
|
|
|
string(types.ConfigTypeVariable),
|
|
|
|
},
|
2019-02-21 15:08:30 +00:00
|
|
|
}
|
2022-02-21 17:07:58 +00:00
|
|
|
dm, err := datamanager.NewDataManager(ctx, log, dmConf)
|
2019-02-21 15:08:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-02-21 17:07:58 +00:00
|
|
|
readDB, err := readdb.NewReadDB(ctx, log, filepath.Join(c.DataDir, "readdb"), e, ost, dm)
|
2019-02-21 15:08:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-04-26 14:00:03 +00:00
|
|
|
cs.dm = dm
|
2019-02-21 15:08:30 +00:00
|
|
|
cs.readDB = readDB
|
|
|
|
|
2022-02-21 17:07:58 +00:00
|
|
|
ah := action.NewActionHandler(log, readDB, dm, e)
|
2019-05-03 21:35:25 +00:00
|
|
|
cs.ah = ah
|
2019-02-21 15:08:30 +00:00
|
|
|
|
|
|
|
return cs, nil
|
|
|
|
}
|
|
|
|
|
2019-07-17 17:52:25 +00:00
|
|
|
func (s *Configstore) setupDefaultRouter() http.Handler {
|
2022-02-21 17:07:58 +00:00
|
|
|
maintenanceModeHandler := api.NewMaintenanceModeHandler(s.log, s.ah, s.e)
|
|
|
|
exportHandler := api.NewExportHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
projectGroupHandler := api.NewProjectGroupHandler(s.log, s.ah, s.readDB)
|
|
|
|
projectGroupSubgroupsHandler := api.NewProjectGroupSubgroupsHandler(s.log, s.ah, s.readDB)
|
|
|
|
projectGroupProjectsHandler := api.NewProjectGroupProjectsHandler(s.log, s.ah, s.readDB)
|
|
|
|
createProjectGroupHandler := api.NewCreateProjectGroupHandler(s.log, s.ah, s.readDB)
|
|
|
|
updateProjectGroupHandler := api.NewUpdateProjectGroupHandler(s.log, s.ah, s.readDB)
|
|
|
|
deleteProjectGroupHandler := api.NewDeleteProjectGroupHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
projectHandler := api.NewProjectHandler(s.log, s.ah, s.readDB)
|
|
|
|
createProjectHandler := api.NewCreateProjectHandler(s.log, s.ah, s.readDB)
|
|
|
|
updateProjectHandler := api.NewUpdateProjectHandler(s.log, s.ah, s.readDB)
|
|
|
|
deleteProjectHandler := api.NewDeleteProjectHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
secretsHandler := api.NewSecretsHandler(s.log, s.ah, s.readDB)
|
|
|
|
createSecretHandler := api.NewCreateSecretHandler(s.log, s.ah)
|
|
|
|
updateSecretHandler := api.NewUpdateSecretHandler(s.log, s.ah)
|
|
|
|
deleteSecretHandler := api.NewDeleteSecretHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
variablesHandler := api.NewVariablesHandler(s.log, s.ah, s.readDB)
|
|
|
|
createVariableHandler := api.NewCreateVariableHandler(s.log, s.ah)
|
|
|
|
updateVariableHandler := api.NewUpdateVariableHandler(s.log, s.ah)
|
|
|
|
deleteVariableHandler := api.NewDeleteVariableHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
userHandler := api.NewUserHandler(s.log, s.readDB)
|
|
|
|
usersHandler := api.NewUsersHandler(s.log, s.readDB)
|
|
|
|
createUserHandler := api.NewCreateUserHandler(s.log, s.ah)
|
|
|
|
updateUserHandler := api.NewUpdateUserHandler(s.log, s.ah)
|
|
|
|
deleteUserHandler := api.NewDeleteUserHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
createUserLAHandler := api.NewCreateUserLAHandler(s.log, s.ah)
|
|
|
|
deleteUserLAHandler := api.NewDeleteUserLAHandler(s.log, s.ah)
|
|
|
|
updateUserLAHandler := api.NewUpdateUserLAHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
createUserTokenHandler := api.NewCreateUserTokenHandler(s.log, s.ah)
|
|
|
|
deleteUserTokenHandler := api.NewDeleteUserTokenHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
userOrgsHandler := api.NewUserOrgsHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
orgHandler := api.NewOrgHandler(s.log, s.readDB)
|
|
|
|
orgsHandler := api.NewOrgsHandler(s.log, s.readDB)
|
|
|
|
createOrgHandler := api.NewCreateOrgHandler(s.log, s.ah)
|
|
|
|
deleteOrgHandler := api.NewDeleteOrgHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
orgMembersHandler := api.NewOrgMembersHandler(s.log, s.ah)
|
|
|
|
addOrgMemberHandler := api.NewAddOrgMemberHandler(s.log, s.ah)
|
|
|
|
removeOrgMemberHandler := api.NewRemoveOrgMemberHandler(s.log, s.ah)
|
|
|
|
|
|
|
|
remoteSourceHandler := api.NewRemoteSourceHandler(s.log, s.readDB)
|
|
|
|
remoteSourcesHandler := api.NewRemoteSourcesHandler(s.log, s.readDB)
|
|
|
|
createRemoteSourceHandler := api.NewCreateRemoteSourceHandler(s.log, s.ah)
|
|
|
|
updateRemoteSourceHandler := api.NewUpdateRemoteSourceHandler(s.log, s.ah)
|
|
|
|
deleteRemoteSourceHandler := api.NewDeleteRemoteSourceHandler(s.log, s.ah)
|
2019-02-21 15:08:30 +00:00
|
|
|
|
|
|
|
router := mux.NewRouter()
|
2019-03-14 13:36:18 +00:00
|
|
|
apirouter := router.PathPrefix("/api/v1alpha").Subrouter().UseEncodedPath()
|
|
|
|
|
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}", projectGroupHandler).Methods("GET")
|
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/subgroups", projectGroupSubgroupsHandler).Methods("GET")
|
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/projects", projectGroupProjectsHandler).Methods("GET")
|
2019-04-08 06:54:45 +00:00
|
|
|
apirouter.Handle("/projectgroups", createProjectGroupHandler).Methods("POST")
|
2019-05-14 15:53:48 +00:00
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}", updateProjectGroupHandler).Methods("PUT")
|
2019-05-12 22:23:57 +00:00
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}", deleteProjectGroupHandler).Methods("DELETE")
|
2019-02-21 15:08:30 +00:00
|
|
|
|
2019-03-14 13:36:18 +00:00
|
|
|
apirouter.Handle("/projects/{projectref}", projectHandler).Methods("GET")
|
2019-04-08 06:54:45 +00:00
|
|
|
apirouter.Handle("/projects", createProjectHandler).Methods("POST")
|
2019-05-09 13:33:57 +00:00
|
|
|
apirouter.Handle("/projects/{projectref}", updateProjectHandler).Methods("PUT")
|
2019-03-14 13:36:18 +00:00
|
|
|
apirouter.Handle("/projects/{projectref}", deleteProjectHandler).Methods("DELETE")
|
|
|
|
|
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/secrets", secretsHandler).Methods("GET")
|
|
|
|
apirouter.Handle("/projects/{projectref}/secrets", secretsHandler).Methods("GET")
|
2019-04-08 06:54:45 +00:00
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/secrets", createSecretHandler).Methods("POST")
|
|
|
|
apirouter.Handle("/projects/{projectref}/secrets", createSecretHandler).Methods("POST")
|
2019-07-08 08:32:32 +00:00
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/secrets/{secretname}", updateSecretHandler).Methods("PUT")
|
|
|
|
apirouter.Handle("/projects/{projectref}/secrets/{secretname}", updateSecretHandler).Methods("PUT")
|
2019-03-14 13:36:18 +00:00
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/secrets/{secretname}", deleteSecretHandler).Methods("DELETE")
|
|
|
|
apirouter.Handle("/projects/{projectref}/secrets/{secretname}", deleteSecretHandler).Methods("DELETE")
|
|
|
|
|
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/variables", variablesHandler).Methods("GET")
|
|
|
|
apirouter.Handle("/projects/{projectref}/variables", variablesHandler).Methods("GET")
|
2019-04-08 06:54:45 +00:00
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/variables", createVariableHandler).Methods("POST")
|
|
|
|
apirouter.Handle("/projects/{projectref}/variables", createVariableHandler).Methods("POST")
|
2019-07-06 13:25:24 +00:00
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/variables/{variablename}", updateVariableHandler).Methods("PUT")
|
|
|
|
apirouter.Handle("/projects/{projectref}/variables/{variablename}", updateVariableHandler).Methods("PUT")
|
2019-03-14 13:36:18 +00:00
|
|
|
apirouter.Handle("/projectgroups/{projectgroupref}/variables/{variablename}", deleteVariableHandler).Methods("DELETE")
|
|
|
|
apirouter.Handle("/projects/{projectref}/variables/{variablename}", deleteVariableHandler).Methods("DELETE")
|
2019-02-21 15:08:30 +00:00
|
|
|
|
2019-05-03 09:07:53 +00:00
|
|
|
apirouter.Handle("/users/{userref}", userHandler).Methods("GET")
|
2019-02-21 15:08:30 +00:00
|
|
|
apirouter.Handle("/users", usersHandler).Methods("GET")
|
2019-04-08 06:54:45 +00:00
|
|
|
apirouter.Handle("/users", createUserHandler).Methods("POST")
|
2019-05-03 09:07:53 +00:00
|
|
|
apirouter.Handle("/users/{userref}", updateUserHandler).Methods("PUT")
|
|
|
|
apirouter.Handle("/users/{userref}", deleteUserHandler).Methods("DELETE")
|
2019-02-21 15:08:30 +00:00
|
|
|
|
2019-05-03 09:07:53 +00:00
|
|
|
apirouter.Handle("/users/{userref}/linkedaccounts", createUserLAHandler).Methods("POST")
|
|
|
|
apirouter.Handle("/users/{userref}/linkedaccounts/{laid}", deleteUserLAHandler).Methods("DELETE")
|
|
|
|
apirouter.Handle("/users/{userref}/linkedaccounts/{laid}", updateUserLAHandler).Methods("PUT")
|
|
|
|
apirouter.Handle("/users/{userref}/tokens", createUserTokenHandler).Methods("POST")
|
|
|
|
apirouter.Handle("/users/{userref}/tokens/{tokenname}", deleteUserTokenHandler).Methods("DELETE")
|
2019-02-21 15:08:30 +00:00
|
|
|
|
2019-05-03 15:40:07 +00:00
|
|
|
apirouter.Handle("/users/{userref}/orgs", userOrgsHandler).Methods("GET")
|
|
|
|
|
2019-05-03 09:07:53 +00:00
|
|
|
apirouter.Handle("/orgs/{orgref}", orgHandler).Methods("GET")
|
2019-02-28 14:52:35 +00:00
|
|
|
apirouter.Handle("/orgs", orgsHandler).Methods("GET")
|
2019-04-08 06:54:45 +00:00
|
|
|
apirouter.Handle("/orgs", createOrgHandler).Methods("POST")
|
2019-05-03 09:07:53 +00:00
|
|
|
apirouter.Handle("/orgs/{orgref}", deleteOrgHandler).Methods("DELETE")
|
2019-05-14 10:57:53 +00:00
|
|
|
apirouter.Handle("/orgs/{orgref}/members", orgMembersHandler).Methods("GET")
|
2019-05-09 14:47:22 +00:00
|
|
|
apirouter.Handle("/orgs/{orgref}/members/{userref}", addOrgMemberHandler).Methods("PUT")
|
2019-05-14 09:20:09 +00:00
|
|
|
apirouter.Handle("/orgs/{orgref}/members/{userref}", removeOrgMemberHandler).Methods("DELETE")
|
2019-02-28 14:52:35 +00:00
|
|
|
|
2019-05-03 09:07:53 +00:00
|
|
|
apirouter.Handle("/remotesources/{remotesourceref}", remoteSourceHandler).Methods("GET")
|
2019-02-21 15:08:30 +00:00
|
|
|
apirouter.Handle("/remotesources", remoteSourcesHandler).Methods("GET")
|
2019-04-08 06:54:45 +00:00
|
|
|
apirouter.Handle("/remotesources", createRemoteSourceHandler).Methods("POST")
|
2019-05-23 08:29:03 +00:00
|
|
|
apirouter.Handle("/remotesources/{remotesourceref}", updateRemoteSourceHandler).Methods("PUT")
|
2019-05-03 09:07:53 +00:00
|
|
|
apirouter.Handle("/remotesources/{remotesourceref}", deleteRemoteSourceHandler).Methods("DELETE")
|
2019-02-21 15:08:30 +00:00
|
|
|
|
2019-07-17 17:52:25 +00:00
|
|
|
apirouter.Handle("/maintenance", maintenanceModeHandler).Methods("PUT", "DELETE")
|
|
|
|
|
|
|
|
apirouter.Handle("/export", exportHandler).Methods("GET")
|
|
|
|
|
|
|
|
mainrouter := mux.NewRouter()
|
|
|
|
mainrouter.PathPrefix("/").Handler(router)
|
|
|
|
|
|
|
|
return mainrouter
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Configstore) setupMaintenanceRouter() http.Handler {
|
2022-02-21 17:07:58 +00:00
|
|
|
maintenanceModeHandler := api.NewMaintenanceModeHandler(s.log, s.ah, s.e)
|
|
|
|
exportHandler := api.NewExportHandler(s.log, s.ah)
|
|
|
|
importHandler := api.NewImportHandler(s.log, s.ah)
|
2019-07-17 17:52:25 +00:00
|
|
|
|
|
|
|
router := mux.NewRouter()
|
|
|
|
apirouter := router.PathPrefix("/api/v1alpha").Subrouter().UseEncodedPath()
|
|
|
|
|
|
|
|
apirouter.Handle("/maintenance", maintenanceModeHandler).Methods("PUT", "DELETE")
|
|
|
|
|
|
|
|
apirouter.Handle("/export", exportHandler).Methods("GET")
|
|
|
|
apirouter.Handle("/import", importHandler).Methods("POST")
|
|
|
|
|
2019-02-21 15:08:30 +00:00
|
|
|
mainrouter := mux.NewRouter()
|
2019-07-13 21:15:00 +00:00
|
|
|
mainrouter.PathPrefix("/").Handler(router)
|
2019-02-21 15:08:30 +00:00
|
|
|
|
2019-07-17 17:52:25 +00:00
|
|
|
return mainrouter
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Configstore) Run(ctx context.Context) error {
|
|
|
|
for {
|
|
|
|
if err := s.run(ctx); err != nil {
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Err(err).Msgf("run error")
|
2019-07-17 17:52:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sleepCh := time.NewTimer(1 * time.Second).C
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
2022-02-21 17:07:58 +00:00
|
|
|
s.log.Info().Msgf("configstore exiting")
|
2019-07-17 17:52:25 +00:00
|
|
|
return nil
|
|
|
|
case <-sleepCh:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Configstore) run(ctx context.Context) error {
|
2019-02-21 15:08:30 +00:00
|
|
|
var tlsConfig *tls.Config
|
|
|
|
if s.c.Web.TLS {
|
|
|
|
var err error
|
|
|
|
tlsConfig, err = util.NewTLSConfig(s.c.Web.TLSCertFile, s.c.Web.TLSKeyFile, "", false)
|
|
|
|
if err != nil {
|
2022-02-21 17:07:58 +00:00
|
|
|
s.log.Err(err).Send()
|
2019-02-21 15:08:30 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-17 17:52:25 +00:00
|
|
|
resp, err := s.e.Get(ctx, common.EtcdMaintenanceKey, 0)
|
2022-02-24 11:56:52 +00:00
|
|
|
if err != nil && !errors.Is(err, etcd.ErrKeyNotFound) {
|
2019-07-17 17:52:25 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
maintenanceMode := false
|
|
|
|
if len(resp.Kvs) > 0 {
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Info().Msgf("maintenance mode key is present")
|
2019-07-17 17:52:25 +00:00
|
|
|
maintenanceMode = true
|
|
|
|
}
|
|
|
|
|
|
|
|
s.maintenanceMode = maintenanceMode
|
|
|
|
s.dm.SetMaintenanceMode(maintenanceMode)
|
|
|
|
s.ah.SetMaintenanceMode(maintenanceMode)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
errCh := make(chan error, 100)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
dmReadyCh := make(chan struct{})
|
|
|
|
|
|
|
|
var mainrouter http.Handler
|
|
|
|
if s.maintenanceMode {
|
|
|
|
mainrouter = s.setupMaintenanceRouter()
|
|
|
|
util.GoWait(&wg, func() { s.maintenanceModeWatcherLoop(ctx, cancel, s.maintenanceMode) })
|
|
|
|
|
|
|
|
} else {
|
|
|
|
mainrouter = s.setupDefaultRouter()
|
|
|
|
|
|
|
|
util.GoWait(&wg, func() { s.maintenanceModeWatcherLoop(ctx, cancel, s.maintenanceMode) })
|
|
|
|
|
|
|
|
// TODO(sgotti) wait for all goroutines exiting
|
|
|
|
util.GoWait(&wg, func() { errCh <- s.dm.Run(ctx, dmReadyCh) })
|
|
|
|
|
|
|
|
// wait for dm to be ready
|
|
|
|
<-dmReadyCh
|
|
|
|
|
|
|
|
util.GoWait(&wg, func() { errCh <- s.readDB.Run(ctx) })
|
|
|
|
}
|
|
|
|
|
2019-02-21 15:08:30 +00:00
|
|
|
httpServer := http.Server{
|
|
|
|
Addr: s.c.Web.ListenAddress,
|
|
|
|
Handler: mainrouter,
|
|
|
|
TLSConfig: tlsConfig,
|
|
|
|
}
|
|
|
|
|
2019-07-17 17:52:25 +00:00
|
|
|
lerrCh := make(chan error, 1)
|
|
|
|
util.GoWait(&wg, func() {
|
2021-03-19 09:52:32 +00:00
|
|
|
if !s.c.Web.TLS {
|
|
|
|
lerrCh <- httpServer.ListenAndServe()
|
|
|
|
} else {
|
|
|
|
lerrCh <- httpServer.ListenAndServeTLS("", "")
|
|
|
|
}
|
2019-07-17 17:52:25 +00:00
|
|
|
})
|
|
|
|
defer httpServer.Close()
|
2019-02-21 15:08:30 +00:00
|
|
|
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Info().Msgf("configstore run exiting")
|
2019-02-21 15:08:30 +00:00
|
|
|
case err := <-lerrCh:
|
2019-07-04 13:50:37 +00:00
|
|
|
if err != nil {
|
2022-02-21 17:07:58 +00:00
|
|
|
log.Err(err).Msgf("http server listen error")
|
2019-07-04 13:50:37 +00:00
|
|
|
return err
|
|
|
|
}
|
2019-02-21 15:08:30 +00:00
|
|
|
case err := <-errCh:
|
2019-07-04 13:50:37 +00:00
|
|
|
if err != nil {
|
2022-02-21 17:07:58 +00:00
|
|
|
s.log.Err(err).Send()
|
2019-07-04 13:50:37 +00:00
|
|
|
return err
|
|
|
|
}
|
2019-02-21 15:08:30 +00:00
|
|
|
}
|
2019-07-04 13:50:37 +00:00
|
|
|
|
2019-07-17 17:52:25 +00:00
|
|
|
cancel()
|
|
|
|
httpServer.Close()
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
return err
|
2019-02-21 15:08:30 +00:00
|
|
|
}
|