mirror of
https://github.com/moul/sshportal.git
synced 2025-09-06 20:54:27 +08:00
Fix some backup/restore bugs + improve MySQL support
This commit is contained in:
parent
511470087b
commit
3c10578584
5 changed files with 120 additions and 28 deletions
|
@ -6,6 +6,8 @@
|
|||
* Connection history
|
||||
* Audit log
|
||||
* Add dynamic strict host key checking (learning on the first time, strict on the next ones)
|
||||
* Add-back MySQL support (experimental)
|
||||
* Fix some backup/restore bugs
|
||||
|
||||
## v1.4.0 (2017-11-24)
|
||||
|
||||
|
|
20
db.go
20
db.go
|
@ -24,8 +24,10 @@ type Config struct {
|
|||
HostGroups []*HostGroup `json:"host_groups"`
|
||||
ACLs []*ACL `json:"acls"`
|
||||
Settings []*Setting `json:"settings"`
|
||||
Events []*Event `json:"events"`
|
||||
Sessions []*Session `json:"sessions"`
|
||||
Date time.Time `json:"date"`
|
||||
// FIXME: add latest migration
|
||||
Date time.Time `json:"date"`
|
||||
}
|
||||
|
||||
type Setting struct {
|
||||
|
@ -118,14 +120,14 @@ type ACL struct {
|
|||
|
||||
type Session struct {
|
||||
gorm.Model
|
||||
StoppedAt time.Time `valid:"optional"`
|
||||
Status string `valid:"required"`
|
||||
User *User `gorm:"ForeignKey:UserID"`
|
||||
Host *Host `gorm:"ForeignKey:HostID"`
|
||||
UserID uint `valid:"optional"`
|
||||
HostID uint `valid:"optional"`
|
||||
ErrMsg string `valid:"optional"`
|
||||
Comment string `valid:"optional"`
|
||||
StoppedAt *time.Time `sql:"index" valid:"optional"`
|
||||
Status string `valid:"required"`
|
||||
User *User `gorm:"ForeignKey:UserID"`
|
||||
Host *Host `gorm:"ForeignKey:HostID"`
|
||||
UserID uint `valid:"optional"`
|
||||
HostID uint `valid:"optional"`
|
||||
ErrMsg string `valid:"optional"`
|
||||
Comment string `valid:"optional"`
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
|
|
39
dbinit.go
39
dbinit.go
|
@ -392,6 +392,45 @@ func dbInit(db *gorm.DB) error {
|
|||
Rollback: func(tx *gorm.DB) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
},
|
||||
}, {
|
||||
ID: "26",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
type Session struct {
|
||||
gorm.Model
|
||||
StoppedAt *time.Time `sql:"index" valid:"optional"`
|
||||
Status string `valid:"required"`
|
||||
User *User `gorm:"ForeignKey:UserID"`
|
||||
Host *Host `gorm:"ForeignKey:HostID"`
|
||||
UserID uint `valid:"optional"`
|
||||
HostID uint `valid:"optional"`
|
||||
ErrMsg string `valid:"optional"`
|
||||
Comment string `valid:"optional"`
|
||||
}
|
||||
return tx.AutoMigrate(&Session{}).Error
|
||||
},
|
||||
Rollback: func(tx *gorm.DB) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
},
|
||||
}, {
|
||||
ID: "27",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
var sessions []Session
|
||||
if err := db.Find(&sessions).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, session := range sessions {
|
||||
if session.StoppedAt != nil && session.StoppedAt.IsZero() {
|
||||
if err := db.Model(&session).Updates(map[string]interface{}{"stopped_at": nil}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
Rollback: func(tx *gorm.DB) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
},
|
||||
},
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
|
|
3
main.go
3
main.go
|
@ -178,7 +178,8 @@ func server(c *cli.Context) error {
|
|||
}
|
||||
}
|
||||
sessUpdate.Status = SessionStatusClosed
|
||||
sessUpdate.StoppedAt = time.Now()
|
||||
now := time.Now()
|
||||
sessUpdate.StoppedAt = &now
|
||||
db.Model(&sess).Updates(&sessUpdate)
|
||||
case "deny":
|
||||
fmt.Fprintf(s, "You don't have permission to that host.\n")
|
||||
|
|
84
shell.go
84
shell.go
|
@ -286,11 +286,11 @@ GLOBAL OPTIONS:
|
|||
}
|
||||
|
||||
config := Config{}
|
||||
if err := db.Find(&config.Hosts).Error; err != nil {
|
||||
if err := HostsPreload(db).Find(&config.Hosts).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := db.Find(&config.SSHKeys).Error; err != nil {
|
||||
if err := SSHKeysPreload(db).Find(&config.SSHKeys).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
for _, key := range config.SSHKeys {
|
||||
|
@ -304,7 +304,7 @@ GLOBAL OPTIONS:
|
|||
}
|
||||
}
|
||||
|
||||
if err := db.Find(&config.Hosts).Error; err != nil {
|
||||
if err := HostsPreload(db).Find(&config.Hosts).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
for _, host := range config.Hosts {
|
||||
|
@ -318,24 +318,30 @@ GLOBAL OPTIONS:
|
|||
}
|
||||
}
|
||||
|
||||
if err := db.Find(&config.UserKeys).Error; err != nil {
|
||||
if err := UserKeysPreload(db).Find(&config.UserKeys).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.Find(&config.Users).Error; err != nil {
|
||||
if err := UsersPreload(db).Find(&config.Users).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.Find(&config.UserGroups).Error; err != nil {
|
||||
if err := UserGroupsPreload(db).Find(&config.UserGroups).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.Find(&config.HostGroups).Error; err != nil {
|
||||
if err := HostGroupsPreload(db).Find(&config.HostGroups).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.Find(&config.ACLs).Error; err != nil {
|
||||
if err := ACLsPreload(db).Find(&config.ACLs).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.Find(&config.Settings).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := SessionsPreload(db).Find(&config.Sessions).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := EventsPreload(db).Find(&config.Events).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
config.Date = time.Now()
|
||||
enc := json.NewEncoder(s)
|
||||
if c.Bool("indent") {
|
||||
|
@ -372,6 +378,8 @@ GLOBAL OPTIONS:
|
|||
fmt.Fprintf(s, "* %d Userkeys\n", len(config.UserKeys))
|
||||
fmt.Fprintf(s, "* %d Users\n", len(config.Users))
|
||||
fmt.Fprintf(s, "* %d Settings\n", len(config.Settings))
|
||||
fmt.Fprintf(s, "* %d Sessions\n", len(config.Sessions))
|
||||
fmt.Fprintf(s, "* %d Events\n", len(config.Events))
|
||||
|
||||
if !c.Bool("confirm") {
|
||||
fmt.Fprintf(s, "restore will erase and replace everything in the database.\nIf you are ok, add the '--confirm' to the restore command\n")
|
||||
|
@ -380,8 +388,36 @@ GLOBAL OPTIONS:
|
|||
|
||||
tx := db.Begin()
|
||||
|
||||
// FIXME: handle different migrations:
|
||||
// 1. drop tables
|
||||
// 2. apply migrations `1` to `<backup-migration-id>`
|
||||
// 3. restore data
|
||||
// 4. continues migrations
|
||||
|
||||
// FIXME: tell the administrator to restart the server
|
||||
// if the master host key changed
|
||||
|
||||
// FIXME: do everything in a transaction
|
||||
for _, tableName := range []string{"hosts", "users", "acls", "host_groups", "user_groups", "ssh_keys", "user_keys", "settings"} {
|
||||
tableNames := []string{
|
||||
"acls",
|
||||
"events",
|
||||
"host_group_acls",
|
||||
"host_groups",
|
||||
"host_host_groups",
|
||||
"hosts",
|
||||
//"migrations",
|
||||
"sessions",
|
||||
"settings",
|
||||
"ssh_keys",
|
||||
"user_group_acls",
|
||||
"user_groups",
|
||||
"user_keys",
|
||||
"user_roles",
|
||||
"user_user_groups",
|
||||
"user_user_roles",
|
||||
"users",
|
||||
}
|
||||
for _, tableName := range tableNames {
|
||||
if err := tx.Exec(fmt.Sprintf("DELETE FROM %s;", tableName)).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
|
@ -394,31 +430,31 @@ GLOBAL OPTIONS:
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err := tx.Create(&host).Error; err != nil {
|
||||
if err := tx.FirstOrCreate(&host).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, user := range config.Users {
|
||||
if err := tx.Create(&user).Error; err != nil {
|
||||
if err := tx.FirstOrCreate(&user).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, acl := range config.ACLs {
|
||||
if err := tx.Create(&acl).Error; err != nil {
|
||||
if err := tx.FirstOrCreate(&acl).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, hostGroup := range config.HostGroups {
|
||||
if err := tx.Create(&hostGroup).Error; err != nil {
|
||||
if err := tx.FirstOrCreate(&hostGroup).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, userGroup := range config.UserGroups {
|
||||
if err := tx.Create(&userGroup).Error; err != nil {
|
||||
if err := tx.FirstOrCreate(&userGroup).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
@ -430,19 +466,31 @@ GLOBAL OPTIONS:
|
|||
return err
|
||||
}
|
||||
}
|
||||
if err := tx.Create(&sshKey).Error; err != nil {
|
||||
if err := tx.FirstOrCreate(&sshKey).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, userKey := range config.UserKeys {
|
||||
if err := tx.Create(&userKey).Error; err != nil {
|
||||
if err := tx.FirstOrCreate(&userKey).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, setting := range config.Settings {
|
||||
if err := tx.Create(&setting).Error; err != nil {
|
||||
if err := tx.FirstOrCreate(&setting).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, session := range config.Sessions {
|
||||
if err := tx.FirstOrCreate(&session).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, event := range config.Events {
|
||||
if err := tx.FirstOrCreate(&event).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
@ -1560,7 +1608,7 @@ GLOBAL OPTIONS:
|
|||
if session.StoppedAt.IsZero() {
|
||||
duration = humanize.RelTime(session.CreatedAt, time.Now(), "", "")
|
||||
} else {
|
||||
duration = humanize.RelTime(session.CreatedAt, session.StoppedAt, "", "")
|
||||
duration = humanize.RelTime(session.CreatedAt, *session.StoppedAt, "", "")
|
||||
}
|
||||
duration = strings.Replace(duration, "now", "1 second", 1)
|
||||
table.Append([]string{
|
||||
|
|
Loading…
Add table
Reference in a new issue