Skip to content

Commit

Permalink
feat(api): unlockdb (#3730)
Browse files Browse the repository at this point in the history
Signed-off-by: Yvonnick Esnault <[email protected]>
  • Loading branch information
yesnault authored and bnjjj committed Dec 14, 2018
1 parent d05855d commit fb5a445
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 6 deletions.
1 change: 1 addition & 0 deletions cli/cdsctl/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var adminCmd = cli.Command{

func adminCommands() []*cobra.Command {
return []*cobra.Command{
adminDatabase(),
adminServices(),
adminHooks(),
adminPlatformModels(),
Expand Down
30 changes: 30 additions & 0 deletions cli/cdsctl/admin_database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"github.com/spf13/cobra"

"github.com/ovh/cds/cli"
)

var adminDatabaseCmd = cli.Command{
Name: "database",
Short: "Manage CDS Database",
}

func adminDatabase() *cobra.Command {
return cli.NewCommand(adminDatabaseCmd, nil, []*cobra.Command{
cli.NewCommand(adminDatabaseUnlockCmd, adminDatabaseUnlockFunc, nil),
})
}

var adminDatabaseUnlockCmd = cli.Command{
Name: "unlock",
Short: "Unlock a pending migration (Use with caution)",
Args: []cli.Arg{
{Name: "id"},
},
}

func adminDatabaseUnlockFunc(v cli.Values) error {
return client.AdminDatabaseMigrationUnlock(v.GetString("id"))
}
1 change: 1 addition & 0 deletions engine/api/api_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func (api *API) InitRouter() {
// Admin
r.Handle("/admin/maintenance", r.POST(api.postMaintenanceHandler, NeedAdmin(true)))
r.Handle("/admin/warning", r.DELETE(api.adminTruncateWarningsHandler, NeedAdmin(true)))
r.Handle("/admin/database/migration/unlock/{id}", r.POST(api.postMigrationUnlockedHandler, NeedAdmin(true)))
r.Handle("/admin/debug", r.GET(api.getProfileIndexHandler, Auth(false)))
r.Handle("/admin/debug/trace", r.POST(api.getTraceHandler, NeedAdmin(true)), r.GET(api.getTraceHandler, NeedAdmin(true)))
r.Handle("/admin/debug/cpu", r.POST(api.getCPUProfileHandler, NeedAdmin(true)), r.GET(api.getCPUProfileHandler, NeedAdmin(true)))
Expand Down
25 changes: 25 additions & 0 deletions engine/api/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package api

import (
"context"
"net/http"

"github.com/gorilla/mux"

"github.com/ovh/cds/engine/api/database/dbmigrate"
"github.com/ovh/cds/engine/service"
"github.com/ovh/cds/sdk"
)

func (api *API) postMigrationUnlockedHandler() service.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
id := vars["id"]

if len(id) == 0 {
return sdk.NewErrorFrom(sdk.ErrWrongRequest, "Id is mandatory. Check id from table gorp_migrations_lock")
}

return dbmigrate.UnlockMigrate(api.mustDB().Db, id)
}
}
5 changes: 3 additions & 2 deletions engine/api/database/dbmigrate/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func Do(DBFunc func() *sql.DB, sqlMigrateDir string, dir migrate.MigrationDirect

_, errExec := migrate.ExecMax(DBFunc(), "postgres", source, dir, limit)

if err := unlockMigrate(DBFunc(), hostname); err != nil {
if err := UnlockMigrate(DBFunc(), hostname); err != nil {
return nil, fmt.Errorf("Cannot unlock migration: %v", err)
}

Expand Down Expand Up @@ -100,7 +100,8 @@ func lockMigrate(db *sql.DB, id string) error {
return nil
}

func unlockMigrate(db *sql.DB, id string) error {
// UnlockMigrate unlocks an ID from table gorp_migrations_lock
func UnlockMigrate(db *sql.DB, id string) error {
// construct a gorp DbMap
dbmap := &gorp.DbMap{Db: db, Dialect: gorp.PostgresDialect{}}
dbmap.AddTableWithName(MigrationLock{}, "gorp_migrations_lock").SetKeys(false, "ID")
Expand Down
7 changes: 3 additions & 4 deletions engine/api/scheduler.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ func (api *API) getSchedulerApplicationPipelineHandler() service.Handler {
///Load application
app, errA := application.LoadByName(api.mustDB(), api.Cache, key, appName, getUser(ctx))
if errA != nil {
return sdk.WrapError(errA, "getSchedulerApplicationPipelineHandler> Cannot load application %s for project %s from db", appName, key)

return sdk.WrapError(errA, "Cannot load application %s for project %s from db", appName, key)
}

//Load pipeline
Expand All @@ -43,9 +42,9 @@ func (api *API) getSchedulerApplicationPipelineHandler() service.Handler {

//Load environment
if err := r.ParseForm(); err != nil {
return sdk.WrapError(sdk.ErrWrongRequest, "getSchedulerApplicationPipelineHandler> Cannot parse form")

return sdk.NewErrorFrom(sdk.ErrWrongRequest, "Cannot parse form")
}

envName := r.Form.Get("envName")
var env *sdk.Environment
if envName != "" {
Expand Down
5 changes: 5 additions & 0 deletions sdk/cdsclient/client_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import (
"github.com/ovh/cds/sdk"
)

func (c *client) AdminDatabaseMigrationUnlock(id string) error {
_, _, _, err := c.Request(context.Background(), "POST", "/admin/database/migration/unlock/"+id, nil)
return err
}

func (c *client) Services() ([]sdk.Service, error) {
srvs := []sdk.Service{}
if _, err := c.GetJSON(context.Background(), "/admin/services", &srvs); err != nil {
Expand Down
1 change: 1 addition & 0 deletions sdk/cdsclient/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type TemplateClient interface {

// AdminService expose all function to CDS services
type AdminService interface {
AdminDatabaseMigrationUnlock(id string) error
Services() ([]sdk.Service, error)
ServicesByName(name string) (*sdk.Service, error)
ServiceDelete(name string) error
Expand Down

0 comments on commit fb5a445

Please sign in to comment.